summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2022-06-30 11:00:30 +0200
committerAleksander Morgado <aleksander@aleksander.es>2022-06-30 11:01:00 +0200
commitfa6c7a972eeaf75cea2a51429ee8017566f9b917 (patch)
treecefabfd5c393420438ba626379f4f6fa7c5a1799
parenta911f6874493a0e6a567cecf4582584312cd8d23 (diff)
downloadlibqmi-fa6c7a972eeaf75cea2a51429ee8017566f9b917.tar.gz
libqmi-glib: remove temp files added incorrectly
Fixes cc590d8dadfd67aae10e56cc4886df21a423d72a
-rw-r--r--src/libqmi-glib/#qmi-device.c#3440
l---------src/libqmi-glib/.#qmi-device.c1
2 files changed, 0 insertions, 3441 deletions
diff --git a/src/libqmi-glib/#qmi-device.c# b/src/libqmi-glib/#qmi-device.c#
deleted file mode 100644
index 3c149154..00000000
--- a/src/libqmi-glib/#qmi-device.c#
+++ /dev/null
@@ -1,3440 +0,0 @@
-/* -*- 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 Lanedo GmbH
- * Copyright (C) 2012-2021 Aleksander Morgado <aleksander@aleksander.es>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "qmi-device.h"
-#include "qmi-message.h"
-#include "qmi-file.h"
-#include "qmi-endpoint.h"
-#include "qmi-endpoint-mbim.h"
-#include "qmi-endpoint-qmux.h"
-#include "qmi-ctl.h"
-#include "qmi-dms.h"
-#include "qmi-wds.h"
-#include "qmi-nas.h"
-#include "qmi-wms.h"
-#include "qmi-pdc.h"
-#include "qmi-pds.h"
-#include "qmi-pbm.h"
-#include "qmi-uim.h"
-#include "qmi-sar.h"
-#include "qmi-oma.h"
-#include "qmi-wda.h"
-#include "qmi-voice.h"
-#include "qmi-loc.h"
-#include "qmi-qos.h"
-#include "qmi-gas.h"
-#include "qmi-gms.h"
-#include "qmi-dsd.h"
-#include "qmi-dpm.h"
-#include "qmi-fox.h"
-#include "qmi-utils.h"
-#include "qmi-helpers.h"
-#include "qmi-error-types.h"
-#include "qmi-enum-types.h"
-#include "qmi-proxy.h"
-#include "qmi-net-port-manager-qmiwwan.h"
-#include "qmi-version.h"
-
-#if QMI_QRTR_SUPPORTED
-# include "qmi-endpoint-qrtr.h"
-# include <libqrtr-glib.h>
-#endif
-
-#if defined RMNET_SUPPORT_ENABLED
-# include "qmi-net-port-manager-rmnet.h"
-#endif
-
-static void async_initable_iface_init (GAsyncInitableIface *iface);
-
-G_DEFINE_TYPE_EXTENDED (QmiDevice, qmi_device, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
-
-enum {
- PROP_0,
- PROP_FILE,
- PROP_NO_FILE_CHECK,
- PROP_PROXY_PATH,
- PROP_WWAN_IFACE,
-#if QMI_QRTR_SUPPORTED
- PROP_NODE,
-#endif
- PROP_LAST
-};
-
-enum {
- SIGNAL_INDICATION,
- SIGNAL_REMOVED,
- SIGNAL_LAST
-};
-
-static GParamSpec *properties[PROP_LAST];
-static guint signals [SIGNAL_LAST] = { 0 };
-
-struct _QmiDevicePrivate {
- /* File or node */
- QmiFile *file;
-#if QMI_QRTR_SUPPORTED
- QrtrNode *node;
-#endif
- gboolean no_file_check;
-
- /* WWAN interface */
- gboolean no_wwan_check;
- gchar *wwan_iface;
-
- /* Information necessary for data port */
- QmiNetPortManager *net_port_manager;
-
- /* Implicit CTL client */
- QmiClientCtl *client_ctl;
- guint sync_indication_id;
-
- /* Supported services */
- GArray *supported_services;
-
- /* Lower-level transport */
- QmiEndpoint *endpoint;
- guint endpoint_new_data_id;
- guint endpoint_hangup_id;
-
- /* Support for qmi-proxy */
- gchar *proxy_path;
-
- /* HT to keep track of ongoing transactions */
- GHashTable *transactions;
-
- /* HT of clients that want to get indications */
- GHashTable *registered_clients;
-};
-
-#if QMI_QRTR_SUPPORTED
-# define QMI_CLIENT_VERSION_UNKNOWN 99
-#endif
-
-/*****************************************************************************/
-/* Message transactions (private) */
-
-typedef struct {
- QmiDevice *self;
- gpointer key;
-} TransactionWaitContext;
-
-typedef struct {
- QmiMessage *message;
- QmiMessageContext *message_context;
- GSimpleAsyncResult *result;
- GSource *timeout_source;
- GCancellable *cancellable;
- gulong cancellable_id;
- TransactionWaitContext *wait_ctx;
-
- /* abortable support */
- GError *abort_error;
- GCancellable *abort_cancellable;
- QmiDeviceCommandAbortableBuildRequestFn abort_build_request_fn;
- QmiDeviceCommandAbortableParseResponseFn abort_parse_response_fn;
- gpointer abort_user_data;
- GDestroyNotify abort_user_data_free;
-} Transaction;
-
-static Transaction *
-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,
- transaction_new);
- if (cancellable)
- tr->cancellable = g_object_ref (cancellable);
-
- return tr;
-}
-
-static void
-transaction_complete_and_free (Transaction *tr,
- QmiMessage *reply,
- const GError *error)
-{
- g_assert (reply != NULL || error != NULL);
-
- /* always set result first, as we may be using one of the GErrors
- * stored in the Transaction as result itself */
- if (reply) {
- /* if we got a valid response, we can cancel any ongoing abort
- * operation for this request */
- if (tr->abort_cancellable) {
- g_debug ("transaction 0x%x completed with a response: cancelling the abort operation",
- qmi_message_get_transaction_id (tr->message));
- g_cancellable_cancel (tr->abort_cancellable);
- }
- g_simple_async_result_set_op_res_gpointer (tr->result,
- qmi_message_ref (reply),
- (GDestroyNotify)qmi_message_unref);
- } else if (error)
- g_simple_async_result_set_from_error (tr->result, error);
- else
- g_assert_not_reached ();
-
- if (tr->timeout_source)
- g_source_destroy (tr->timeout_source);
-
- if (tr->cancellable) {
- if (tr->cancellable_id)
- g_cancellable_disconnect (tr->cancellable, tr->cancellable_id);
- g_object_unref (tr->cancellable);
- }
-
- if (tr->wait_ctx)
- g_slice_free (TransactionWaitContext, tr->wait_ctx);
-
- if (tr->abort_error)
- g_error_free (tr->abort_error);
-
- if (tr->abort_cancellable)
- g_object_unref (tr->abort_cancellable);
-
- if (tr->abort_user_data && tr->abort_user_data_free)
- tr->abort_user_data_free (tr->abort_user_data);
-
- 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);
-}
-
-static inline gpointer
-build_transaction_key (QmiMessage *message)
-{
- gpointer key;
- guint8 service;
- guint8 client_id;
- guint16 transaction_id;
-
- service = (guint8)qmi_message_get_service (message);
- client_id = qmi_message_get_client_id (message);
- transaction_id = qmi_message_get_transaction_id (message);
-
- /* We're putting a 32 bit value into a gpointer */
- key = GUINT_TO_POINTER ((((service << 8) | client_id) << 16) | transaction_id);
-
- return key;
-}
-
-static Transaction *
-device_peek_transaction (QmiDevice *self,
- gconstpointer key)
-{
- return g_hash_table_lookup (self->priv->transactions, key);
-}
-
-static Transaction *
-device_release_transaction (QmiDevice *self,
- gconstpointer key)
-{
- Transaction *tr = NULL;
-
- /* If found, remove it from the HT */
- tr = device_peek_transaction (self, key);
- if (tr)
- g_hash_table_remove (self->priv->transactions, key);
-
- return tr;
-}
-
-static void
-transaction_abort_ready (QmiDevice *self,
- GAsyncResult *res,
- gpointer key)
-{
- Transaction *tr;
- GError *error = NULL;
- QmiMessage *abort_response;
-
- /* Always try to remove from the HT at this point. Note that the transaction
- * pointer may be NULL already, e.g. if the abort was cancelled. In this case
- * we totally ignore the result of the abort operation. */
- tr = device_release_transaction (self, key);
- if (!tr) {
- g_debug ("not processing abort response, operation has already been completed");
- return;
- }
-
- g_assert (tr->abort_parse_response_fn);
-
- abort_response = qmi_device_command_full_finish (self, res, &error);
- if (!abort_response ||
- !tr->abort_parse_response_fn (self,
- abort_response,
- tr->abort_user_data,
- &error)) {
- GError *built_error;
-
- g_debug ("abort operation failed: %s", error->message);
-
- /* We don't want to return any kind of error, because what failed here
- * is the abort operation for the user request, so always return
- * QMI_CORE_ERROR_FAILED and provide the description on the error
- * in the message. */
- built_error = g_error_new (QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "operation failed and couldn't be aborted: %s",
- error->message);
- g_error_free (error);
-
- transaction_complete_and_free (tr, NULL, built_error);
- g_error_free (built_error);
- } else {
- /* aborted successfully */
- g_debug ("operation aborted successfully");
- g_assert (tr->abort_error);
- transaction_complete_and_free (tr, NULL, tr->abort_error);
- }
-
- if (abort_response)
- qmi_message_unref (abort_response);
-}
-
-static void
-transaction_abort (QmiDevice *self,
- Transaction *tr,
- GError *abort_error_take)
-{
- QmiMessage *abort_request;
- GError *error = NULL;
- guint16 transaction_id;
-
- transaction_id = qmi_message_get_transaction_id (tr->message);
-
- /* If the command is not abortable, we'll return the error right away
- * to the user. */
- if (!__qmi_message_is_abortable (tr->message, tr->message_context)) {
- g_debug ("transaction 0x%x aborted, but message is not abortable", transaction_id);
- device_release_transaction (self, tr->wait_ctx->key);
- transaction_complete_and_free (tr, NULL, abort_error_take);
- g_error_free (abort_error_take);
- return;
- }
-
- /* if the command is abortable but the user didn't use qmi_device_command_abortable(),
- * then return the error right away anyway */
- if (!tr->abort_build_request_fn || !tr->abort_parse_response_fn) {
- g_debug ("transaction 0x%x aborted, but no way to build abort request", transaction_id);
- device_release_transaction (self, tr->wait_ctx->key);
- transaction_complete_and_free (tr, NULL, abort_error_take);
- g_error_free (abort_error_take);
- return;
- }
-
- g_debug ("transaction 0x%x aborted, building abort request...", transaction_id);
-
- /* Try to build abort request */
- abort_request = tr->abort_build_request_fn (self,
- tr->message,
- tr->abort_user_data,
- &error);
- if (!abort_request) {
- /* complete the transaction with the error we got while building the
- * abort request */
- g_debug ("transaction 0x%x aborted, but building abort request failed", transaction_id);
- device_release_transaction (self, tr->wait_ctx->key);
- transaction_complete_and_free (tr, NULL, error);
- g_error_free (error);
- return;
- }
-
- /* If command is abortable, let's abort the operation in the
- * device. We'll store the specific abort error to use once the abort
- * operation has been acknowledged by the device. */
- tr->abort_error = abort_error_take;
- tr->abort_cancellable = g_cancellable_new ();
-
- qmi_device_command_full (self,
- abort_request,
- NULL,
- 30,
- tr->abort_cancellable,
- (GAsyncReadyCallback) transaction_abort_ready,
- tr->wait_ctx->key);
-
- qmi_message_unref (abort_request);
-}
-
-static gboolean
-transaction_timed_out (TransactionWaitContext *ctx)
-{
- Transaction *tr;
- GError *error = NULL;
-
- /* A timed out transaction is always tracked */
- tr = device_peek_transaction (ctx->self, ctx->key);
- g_assert (tr);
-
- tr->timeout_source = NULL;
-
- error = g_error_new (QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT, "Transaction timed out");
- transaction_abort (ctx->self, tr, error);
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-transaction_cancelled (GCancellable *cancellable,
- TransactionWaitContext *ctx)
-{
- Transaction *tr;
- GError *error = NULL;
-
- tr = device_peek_transaction (ctx->self, ctx->key);
-
- /* The transaction may have already been cancelled before we stored it in
- * the tracking table, which means the command was NOT sent to the device
- * and we can safely ignore the cancellation request. */
- if (!tr)
- return;
-
- tr->cancellable_id = 0;
-
- error = g_error_new (QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ABORTED, "Transaction aborted");
- transaction_abort (ctx->self, tr, error);
-}
-
-static gboolean
-device_store_transaction (QmiDevice *self,
- Transaction *tr,
- guint timeout,
- GError **error)
-{
- gpointer key;
- Transaction *existing;
-
- key = build_transaction_key (tr->message);
-
- /* Setup the timeout and cancellation */
-
- tr->wait_ctx = g_slice_new (TransactionWaitContext);
- tr->wait_ctx->self = self;
- tr->wait_ctx->key = key; /* valid as long as the transaction is in the HT */
-
- /* Timeout is optional (e.g. disabled when MBIM is used) */
- if (timeout > 0) {
- tr->timeout_source = g_timeout_source_new_seconds (timeout);
- g_source_set_callback (tr->timeout_source, (GSourceFunc)transaction_timed_out, tr->wait_ctx, NULL);
- g_source_attach (tr->timeout_source, g_main_context_get_thread_default ());
- g_source_unref (tr->timeout_source);
- }
-
- if (tr->cancellable) {
- /* Note: transaction_cancelled() will also be called directly if the
- * cancellable is already cancelled */
- tr->cancellable_id = g_cancellable_connect (tr->cancellable,
- (GCallback)transaction_cancelled,
- tr->wait_ctx,
- NULL);
- if (!tr->cancellable_id) {
- g_set_error (error,
- QMI_PROTOCOL_ERROR,
- QMI_PROTOCOL_ERROR_ABORTED,
- "Request is already cancelled");
- return FALSE;
- }
- }
-
- /* If we have already a transaction with the same ID complete the existing
- * one with an error before the new one is added, or we'll end up with
- * dangling timeouts and cancellation handlers that may be fired off later
- * on. */
- existing = device_release_transaction (self, key);
- if (existing) {
- GError *inner_error;
-
- /* Complete transaction with an abort error */
- inner_error = g_error_new (QMI_PROTOCOL_ERROR,
- QMI_PROTOCOL_ERROR_ABORTED,
- "Transaction overwritten");
- transaction_complete_and_free (existing, NULL, inner_error);
- g_error_free (inner_error);
- }
-
- /* Keep in the HT */
- g_hash_table_insert (self->priv->transactions, key, tr);
-
- return TRUE;
-}
-
-static Transaction *
-device_match_transaction (QmiDevice *self,
- QmiMessage *message)
-{
- /* msg can be either the original message or the response */
- return device_release_transaction (self, build_transaction_key (message));
-}
-
-/*****************************************************************************/
-
-static void
-device_hangup_transactions (QmiDevice *self)
-{
- GHashTableIter iter;
- gpointer key, value;
- g_autoptr(GError) common_error = NULL;
-
- common_error = g_error_new (QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED, "endpoint hangup");
-
- g_hash_table_iter_init (&iter, self->priv->transactions);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- Transaction *tr = value;
-
- transaction_complete_and_free (tr, NULL, common_error);
- g_hash_table_iter_remove (&iter);
- }
-}
-
-/*****************************************************************************/
-/* Version info request */
-
-GArray *
-qmi_device_get_service_version_info_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_pointer (G_TASK (res), error);
-}
-
-static void
-version_info_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- GArray *service_list = NULL;
- GArray *out;
- QmiMessageCtlGetVersionInfoOutput *output;
- GError *error = NULL;
- guint i;
-
- /* Check result of the async operation */
- output = qmi_client_ctl_get_version_info_finish (client_ctl, res, &error);
- if (!output) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_get_version_info_output_get_result (output, &error)) {
- qmi_message_ctl_get_version_info_output_unref (output);
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* QMI operation succeeded, we can now get the outputs */
- qmi_message_ctl_get_version_info_output_get_service_list (output, &service_list, NULL);
- out = g_array_sized_new (FALSE, FALSE, sizeof (QmiDeviceServiceVersionInfo), service_list->len);
- for (i = 0; i < service_list->len; i++) {
- QmiMessageCtlGetVersionInfoOutputServiceListService *info;
- QmiDeviceServiceVersionInfo outinfo;
-
- info = &g_array_index (service_list,
- QmiMessageCtlGetVersionInfoOutputServiceListService,
- i);
- outinfo.service = info->service;
- outinfo.major_version = info->major_version;
- outinfo.minor_version = info->minor_version;
- g_array_append_val (out, outinfo);
- }
-
- qmi_message_ctl_get_version_info_output_unref (output);
- g_task_return_pointer (task, out, (GDestroyNotify)g_array_unref);
- g_object_unref (task);
-}
-
-void
-qmi_device_get_service_version_info (QmiDevice *self,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- qmi_client_ctl_get_version_info (
- self->priv->client_ctl,
- NULL,
- timeout,
- cancellable,
- (GAsyncReadyCallback)version_info_ready,
- g_task_new (self, cancellable, callback, user_data));
-}
-
-/*****************************************************************************/
-/* Version info checks (private) */
-
-static const QmiMessageCtlGetVersionInfoOutputServiceListService *
-find_service_version_info (QmiDevice *self,
- QmiService service)
-{
- guint i;
-
- if (!self->priv->supported_services)
- return NULL;
-
- for (i = 0; i < self->priv->supported_services->len; i++) {
- const QmiMessageCtlGetVersionInfoOutputServiceListService *info;
-
- info = &g_array_index (self->priv->supported_services,
- QmiMessageCtlGetVersionInfoOutputServiceListService,
- i);
-
- if (service == info->service)
- return info;
- }
-
- return NULL;
-}
-
-static gboolean
-check_service_supported (QmiDevice *self,
- QmiService service)
-{
- /* If we didn't check supported services, just assume it is supported */
- if (!self->priv->supported_services) {
- g_debug ("[%s] Assuming service '%s' is supported...",
- qmi_file_get_path_display (self->priv->file),
- qmi_service_get_string (service));
- return TRUE;
- }
-
- return !!find_service_version_info (self, service);
-}
-
-/*****************************************************************************/
-
-GFile *
-qmi_device_get_file (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return qmi_file_get_file (self->priv->file);
-}
-
-GFile *
-qmi_device_peek_file (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return qmi_file_peek_file (self->priv->file);
-}
-
-const gchar *
-qmi_device_get_path (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return qmi_file_get_path (self->priv->file);
-}
-
-const gchar *
-qmi_device_get_path_display (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return qmi_file_get_path_display (self->priv->file);
-}
-
-gboolean
-qmi_device_is_open (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), FALSE);
-
- return !!self->priv->endpoint && qmi_endpoint_is_open (self->priv->endpoint);
-}
-
-/*****************************************************************************/
-/* WWAN iface name
- * Always reload from scratch, to handle possible net interface renames */
-
-static void
-reload_wwan_iface_name (QmiDevice *self)
-{
- g_autofree gchar *cdc_wdm_device_name = NULL;
- guint i;
- g_autoptr(GError) error = NULL;
- static const gchar *driver_names[] = { "usbmisc", /* kernel >= 3.6 */
- "usb" }; /* kernel < 3.6 */
-
-#if QMI_QRTR_SUPPORTED
- /* QRTR doesn't have a device file in sysfs, exit right away */
- if (self->priv->node)
- return;
-#endif
-
- g_clear_pointer (&self->priv->wwan_iface, g_free);
-
- cdc_wdm_device_name = qmi_helpers_get_devname (qmi_file_get_path (self->priv->file), &error);
- if (!cdc_wdm_device_name) {
- g_warning ("[%s] invalid path for cdc-wdm control port: %s",
- qmi_file_get_path_display (self->priv->file),
- error->message);
- return;
- }
-
- for (i = 0; i < G_N_ELEMENTS (driver_names) && !self->priv->wwan_iface; i++) {
- g_autofree gchar *sysfs_path = NULL;
- g_autoptr(GFile) sysfs_file = NULL;
- g_autoptr(GFileEnumerator) enumerator = NULL;
- GFileInfo *file_info = NULL;
-
- /* WWAN iface name loading only applicable for qmi_wwan driver right now
- * (so QMI port exposed by the cdc-wdm driver in the usbmisc subsystem),
- * not for QRTR or any other subsystem or driver */
- sysfs_path = g_strdup_printf ("/sys/class/%s/%s/device/net/", driver_names[i], cdc_wdm_device_name);
- sysfs_file = g_file_new_for_path (sysfs_path);
- enumerator = g_file_enumerate_children (sysfs_file,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NONE,
- NULL,
- NULL);
- if (!enumerator)
- continue;
-
- /* Ignore errors when enumerating */
- while ((file_info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
- const gchar *name;
-
- name = g_file_info_get_name (file_info);
- if (name) {
- /* We only expect ONE file in the sysfs directory corresponding
- * to this control port, if more found for any reason, warn about it */
- if (self->priv->wwan_iface)
- g_warning ("[%s] invalid additional wwan iface found: %s",
- qmi_file_get_path_display (self->priv->file), name);
- else
- self->priv->wwan_iface = g_strdup (name);
- }
- g_object_unref (file_info);
- }
- if (!self->priv->wwan_iface)
- g_warning ("[%s] wwan iface not found", qmi_file_get_path_display (self->priv->file));
- }
-
- /* wwan_iface won't be set at this point if the kernel driver in use isn't in
- * the usbmisc subsystem */
-}
-
-const gchar *
-qmi_device_get_wwan_iface (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- reload_wwan_iface_name (self);
- return self->priv->wwan_iface;
-}
-
-/*****************************************************************************/
-/* Expected data format */
-
-static gboolean
-validate_yes_or_no (const gchar value,
- GError **error)
-{
- if (value != 'Y' && value != 'N') {
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Unexpected sysfs file contents: %c", value);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gchar *
-build_raw_ip_sysfs_path (QmiDevice *self)
-{
- return g_strdup_printf ("/sys/class/net/%s/qmi/raw_ip", self->priv->wwan_iface);
-}
-
-static gchar *
-build_pass_through_sysfs_path (QmiDevice *self)
-{
- return g_strdup_printf ("/sys/class/net/%s/qmi/pass_through", self->priv->wwan_iface);
-}
-
-static gboolean
-get_expected_data_format (QmiDevice *self,
- const gchar *raw_ip_sysfs_path,
- const gchar *pass_through_sysfs_path,
- GError **error)
-{
- gchar raw_ip_value = '\0';
- gchar pass_through_value = '\0';
-
- if (!qmi_helpers_read_sysfs_file (raw_ip_sysfs_path, &raw_ip_value, 1, error) ||
- !validate_yes_or_no (raw_ip_value, error))
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
-
- if (raw_ip_value == 'N')
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3;
-
- if (qmi_helpers_read_sysfs_file (pass_through_sysfs_path, &pass_through_value, 1, NULL) &&
- (pass_through_value == 'Y'))
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_QMAP_PASS_THROUGH;
-
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP;
-}
-
-static gboolean
-set_expected_data_format (QmiDevice *self,
- const gchar *raw_ip_sysfs_path,
- const gchar *pass_through_sysfs_path,
- QmiDeviceExpectedDataFormat requested,
- GError **error)
-{
- if (requested == QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3) {
- qmi_helpers_write_sysfs_file (pass_through_sysfs_path, "N", NULL);
- return qmi_helpers_write_sysfs_file (raw_ip_sysfs_path, "N", error);
- }
-
- if (requested == QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP) {
- qmi_helpers_write_sysfs_file (pass_through_sysfs_path, "N", NULL);
- return qmi_helpers_write_sysfs_file (raw_ip_sysfs_path, "Y", error);
- }
-
- if (requested == QMI_DEVICE_EXPECTED_DATA_FORMAT_QMAP_PASS_THROUGH) {
- return (qmi_helpers_write_sysfs_file (raw_ip_sysfs_path, "Y", error) &&
- qmi_helpers_write_sysfs_file (pass_through_sysfs_path, "Y", error));
- }
-
- g_assert_not_reached ();
-}
-
-static QmiDeviceExpectedDataFormat
-common_get_set_expected_data_format (QmiDevice *self,
- QmiDeviceExpectedDataFormat requested,
- GError **error)
-{
- g_autofree gchar *raw_ip = NULL;
- g_autofree gchar *pass_through = NULL;
- QmiDeviceExpectedDataFormat expected = QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
- gboolean readonly;
-
- /* Make sure we load the WWAN iface name */
- reload_wwan_iface_name (self);
-
- /* Expected data format setting and getting is only supported in the qmi_wwan
- * driver, same as the WWAN iface name detection. Therefore, if we cannot load
- * the WWAN iface name we can safely assume that we're not using the qmi_wwan
- * driver. */
- if (!self->priv->wwan_iface) {
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_UNSUPPORTED,
- "Setting expected data format management is unsupported by the driver");
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
- }
-
- readonly = (requested == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN);
-
- /* Build sysfs file paths */
- raw_ip = build_raw_ip_sysfs_path (self);
- pass_through = build_pass_through_sysfs_path (self);
-
- /* Set operation? */
- if (!readonly && !set_expected_data_format (self, raw_ip, pass_through, requested, error))
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
-
- /* Get/Set operations */
- if ((expected = get_expected_data_format (self, raw_ip, pass_through, error)) == QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN)
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
-
- /* If we requested an update but we didn't read that value, report an error */
- if (!readonly && (requested != expected)) {
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Expected data format not updated properly to '%s': got '%s' instead",
- qmi_device_expected_data_format_get_string (requested),
- qmi_device_expected_data_format_get_string (expected));
- return QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN;
- }
-
- /* If the set operation succeeds, we clear the net port manager, as we may need to use a
- * different one */
- g_clear_object (&self->priv->net_port_manager);
-
- return expected;
-}
-
-QmiDeviceExpectedDataFormat
-qmi_device_get_expected_data_format (QmiDevice *self,
- GError **error)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN);
-
- return common_get_set_expected_data_format (self, QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN, error);
-}
-
-gboolean
-qmi_device_set_expected_data_format (QmiDevice *self,
- QmiDeviceExpectedDataFormat format,
- GError **error)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), FALSE);
-
- return (common_get_set_expected_data_format (self, format, error) != QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN);
-}
-
-gboolean
-qmi_device_check_expected_data_format_supported (QmiDevice *self,
- QmiDeviceExpectedDataFormat format,
- GError **error)
-{
- g_autofree gchar *sysfs_path = NULL;
- gchar value = '\0';
-
- g_return_val_if_fail (QMI_IS_DEVICE (self), FALSE);
-
- switch (format) {
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
- return TRUE;
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
- reload_wwan_iface_name (self);
- sysfs_path = build_raw_ip_sysfs_path (self);
- break;
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_QMAP_PASS_THROUGH:
- reload_wwan_iface_name (self);
- sysfs_path = build_pass_through_sysfs_path (self);
- break;
- default:
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN:
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Unknown expected data format given: 0x%x", format);
- return FALSE;
- }
-
- g_assert (sysfs_path);
- return (qmi_helpers_read_sysfs_file (sysfs_path, &value, 1, error) &&
- validate_yes_or_no (value, error));
-}
-
-/*****************************************************************************/
-/* Register/Unregister clients that want to receive indications */
-
-static gpointer
-build_registered_client_key (guint8 cid,
- QmiService service)
-{
- return GUINT_TO_POINTER (((guint8)service << 8) | cid);
-}
-
-static gboolean
-register_client (QmiDevice *self,
- QmiClient *client,
- GError **error)
-{
- gpointer key;
-
- key = build_registered_client_key (qmi_client_get_cid (client),
- qmi_client_get_service (client));
- /* Only add the new client if not already registered one with the same CID
- * for the same service */
- if (g_hash_table_lookup (self->priv->registered_clients, key)) {
- g_set_error (error,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_FAILED,
- "A client with CID '%u' and service '%s' is already registered",
- qmi_client_get_cid (client),
- qmi_service_get_string (qmi_client_get_service (client)));
- return FALSE;
- }
-
- g_hash_table_insert (self->priv->registered_clients,
- key,
- g_object_ref (client));
- return TRUE;
-}
-
-static void
-unregister_client (QmiDevice *self,
- QmiClient *client)
-{
- g_hash_table_remove (self->priv->registered_clients,
- build_registered_client_key (qmi_client_get_cid (client),
- qmi_client_get_service (client)));
-}
-
-/*****************************************************************************/
-/* Allocate new client */
-
-typedef struct {
- QmiService service;
- GType client_type;
- guint8 cid;
-} AllocateClientContext;
-
-static void
-allocate_client_context_free (AllocateClientContext *ctx)
-{
- g_slice_free (AllocateClientContext, ctx);
-}
-
-QmiClient *
-qmi_device_allocate_client_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_pointer (G_TASK (res), error);
-}
-
-static void
-build_client_object (GTask *task)
-{
- QmiDevice *self;
- AllocateClientContext *ctx;
- gchar *version_string = NULL;
- QmiClient *client;
- GError *error = NULL;
- const QmiMessageCtlGetVersionInfoOutputServiceListService *version_info;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* We now have a proper CID for the client, we should be able to create it
- * right away */
- client = g_object_new (ctx->client_type,
- QMI_CLIENT_DEVICE, self,
- QMI_CLIENT_SERVICE, ctx->service,
- QMI_CLIENT_CID, ctx->cid,
- NULL);
-
- /* Add version info to the client if it was retrieved */
- version_info = find_service_version_info (self, ctx->service);
- if (version_info)
- g_object_set (client,
- QMI_CLIENT_VERSION_MAJOR, version_info->major_version,
- QMI_CLIENT_VERSION_MINOR, version_info->minor_version,
- NULL);
-#if QMI_QRTR_SUPPORTED
- else if (self->priv->node) {
- /* QRTR does not have any way of fetching version information. Assume
- * all services can handle all message types and TLVs. */
- g_debug ("[%s] Client version cannot be retrieved when using QRTR",
- qmi_file_get_path_display (self->priv->file));
- g_object_set (client,
- QMI_CLIENT_VERSION_MAJOR, QMI_CLIENT_VERSION_UNKNOWN,
- QMI_CLIENT_VERSION_MINOR, QMI_CLIENT_VERSION_UNKNOWN,
- NULL);
- }
-#endif
-
- /* Register the client to get indications */
- if (!register_client (self, client, &error)) {
- g_prefix_error (&error,
- "Cannot register new client with CID '%u' and service '%s'",
- ctx->cid,
- qmi_service_get_string (ctx->service));
- g_task_return_error (task, error);
- g_object_unref (task);
- g_object_unref (client);
- return;
- }
-
- /* Build version string for the logging */
- if (self->priv->supported_services) {
- const QmiMessageCtlGetVersionInfoOutputServiceListService *info;
-
- info = find_service_version_info (self, ctx->service);
- if (info)
- version_string = g_strdup_printf ("%u.%u", info->major_version, info->minor_version);
- }
-
- g_debug ("[%s] Registered '%s' (version %s) client with ID '%u'",
- qmi_file_get_path_display (self->priv->file),
- qmi_service_get_string (ctx->service),
- version_string ? version_string : "unknown",
- ctx->cid);
-
- g_free (version_string);
-
- /* Client created and registered, complete successfully */
- g_task_return_pointer (task, client, g_object_unref);
- g_object_unref (task);
-}
-
-static void
-allocate_cid_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- QmiMessageCtlAllocateCidOutput *output;
- QmiService service;
- guint8 cid;
- GError *error = NULL;
- AllocateClientContext *ctx;
-
- /* Check result of the async operation */
- output = qmi_client_ctl_allocate_cid_finish (client_ctl, res, &error);
- if (!output) {
- g_prefix_error (&error, "CID allocation failed in the CTL client: ");
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_allocate_cid_output_get_result (output, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- qmi_message_ctl_allocate_cid_output_unref (output);
- return;
- }
-
- /* Allocation info is mandatory when result is success */
- g_assert (qmi_message_ctl_allocate_cid_output_get_allocation_info (output, &service, &cid, NULL));
-
- ctx = g_task_get_task_data (task);
-
- if (service != ctx->service) {
- g_task_return_new_error (
- task,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_FAILED,
- "CID allocation failed in the CTL client: "
- "Service mismatch (requested '%s', got '%s')",
- qmi_service_get_string (ctx->service),
- qmi_service_get_string (service));
- g_object_unref (task);
- qmi_message_ctl_allocate_cid_output_unref (output);
- return;
- }
-
- ctx->cid = cid;
- build_client_object (task);
- qmi_message_ctl_allocate_cid_output_unref (output);
-}
-
-void
-qmi_device_allocate_client (QmiDevice *self,
- QmiService service,
- guint8 cid,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- AllocateClientContext *ctx;
- GTask *task;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (service != QMI_SERVICE_UNKNOWN);
-
- ctx = g_slice_new0 (AllocateClientContext);
- ctx->service = service;
- ctx->client_type = G_TYPE_INVALID;
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_task_data (task,
- ctx,
- (GDestroyNotify)allocate_client_context_free);
-
- /* Check if the requested service is supported by the device */
- if (!check_service_supported (self, service)) {
- g_task_return_new_error (task,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_UNSUPPORTED,
- "Service '%s' not supported by the device",
- qmi_service_get_string (service));
- g_object_unref (task);
- return;
- }
-
- switch (service) {
- case QMI_SERVICE_CTL:
- g_task_return_new_error (task,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_INVALID_ARGS,
- "Cannot create additional clients for the CTL service");
- g_object_unref (task);
- return;
- case QMI_SERVICE_DMS:
-#if defined HAVE_QMI_SERVICE_DMS
- ctx->client_type = QMI_TYPE_CLIENT_DMS;
-#endif
- break;
- case QMI_SERVICE_WDS:
-#if defined HAVE_QMI_SERVICE_WDS
- ctx->client_type = QMI_TYPE_CLIENT_WDS;
-#endif
- break;
- case QMI_SERVICE_NAS:
-#if defined HAVE_QMI_SERVICE_NAS
- ctx->client_type = QMI_TYPE_CLIENT_NAS;
-#endif
- break;
- case QMI_SERVICE_WMS:
-#if defined HAVE_QMI_SERVICE_WMS
- ctx->client_type = QMI_TYPE_CLIENT_WMS;
-#endif
- break;
- case QMI_SERVICE_PDS:
-#if defined HAVE_QMI_SERVICE_PDS
- ctx->client_type = QMI_TYPE_CLIENT_PDS;
-#endif
- break;
- case QMI_SERVICE_PDC:
-#if defined HAVE_QMI_SERVICE_PDC
- ctx->client_type = QMI_TYPE_CLIENT_PDC;
-#endif
- break;
- case QMI_SERVICE_PBM:
-#if defined HAVE_QMI_SERVICE_PBM
- ctx->client_type = QMI_TYPE_CLIENT_PBM;
-#endif
- break;
- case QMI_SERVICE_UIM:
-#if defined HAVE_QMI_SERVICE_UIM
- ctx->client_type = QMI_TYPE_CLIENT_UIM;
-#endif
- break;
- case QMI_SERVICE_OMA:
-#if defined HAVE_QMI_SERVICE_OMA
- ctx->client_type = QMI_TYPE_CLIENT_OMA;
-#endif
- break;
- case QMI_SERVICE_GAS:
-#if defined HAVE_QMI_SERVICE_GAS
- ctx->client_type = QMI_TYPE_CLIENT_GAS;
-#endif
- break;
- case QMI_SERVICE_GMS:
-#if defined HAVE_QMI_SERVICE_GMS
- ctx->client_type = QMI_TYPE_CLIENT_GMS;
-#endif
- break;
- case QMI_SERVICE_WDA:
-#if defined HAVE_QMI_SERVICE_WDA
- ctx->client_type = QMI_TYPE_CLIENT_WDA;
-#endif
- break;
- case QMI_SERVICE_VOICE:
-#if defined HAVE_QMI_SERVICE_VOICE
- ctx->client_type = QMI_TYPE_CLIENT_VOICE;
-#endif
- break;
- case QMI_SERVICE_LOC:
-#if defined HAVE_QMI_SERVICE_LOC
- ctx->client_type = QMI_TYPE_CLIENT_LOC;
-#endif
- break;
- case QMI_SERVICE_QOS:
-#if defined HAVE_QMI_SERVICE_QOS
- ctx->client_type = QMI_TYPE_CLIENT_QOS;
-#endif
- break;
- case QMI_SERVICE_DSD:
-#if defined HAVE_QMI_SERVICE_DSD
- ctx->client_type = QMI_TYPE_CLIENT_DSD;
-#endif
- break;
- case QMI_SERVICE_SAR:
-#if defined HAVE_QMI_SERVICE_SAR
- ctx->client_type = QMI_TYPE_CLIENT_SAR;
-#endif
- break;
- case QMI_SERVICE_DPM:
-#if defined HAVE_QMI_SERVICE_DPM
- ctx->client_type = QMI_TYPE_CLIENT_DPM;
-#endif
- break;
- case QMI_SERVICE_FOX:
-#if defined HAVE_QMI_SERVICE_FOX
- ctx->client_type = QMI_TYPE_CLIENT_FOX;
-#endif
- break;
-
- case QMI_SERVICE_UNKNOWN:
- g_assert_not_reached ();
-
- case QMI_SERVICE_AUTH:
- case QMI_SERVICE_AT:
- case QMI_SERVICE_CAT2:
- case QMI_SERVICE_QCHAT:
- case QMI_SERVICE_RMTFS:
- case QMI_SERVICE_TEST:
- case QMI_SERVICE_IMS:
- case QMI_SERVICE_ADC:
- case QMI_SERVICE_CSD:
- case QMI_SERVICE_MFS:
- case QMI_SERVICE_TIME:
- case QMI_SERVICE_TS:
- case QMI_SERVICE_TMD:
- case QMI_SERVICE_SAP:
- case QMI_SERVICE_TSYNC:
- case QMI_SERVICE_RFSA:
- case QMI_SERVICE_CSVT:
- case QMI_SERVICE_QCMAP:
- case QMI_SERVICE_IMSP:
- case QMI_SERVICE_IMSVT:
- case QMI_SERVICE_IMSA:
- case QMI_SERVICE_COEX:
- case QMI_SERVICE_STX:
- case QMI_SERVICE_BIT:
- case QMI_SERVICE_IMSRTP:
- case QMI_SERVICE_RFRPE:
- case QMI_SERVICE_SSCTL:
- case QMI_SERVICE_CAT:
- case QMI_SERVICE_RMS:
- case QMI_SERVICE_FOTA:
- default:
- break;
- }
-
- if (ctx->client_type == G_TYPE_INVALID) {
- g_task_return_new_error (task, QMI_CORE_ERROR, QMI_CORE_ERROR_INVALID_ARGS,
- "Clients for service '%s' not supported",
- qmi_service_get_string (service));
- g_object_unref (task);
- return;
- }
-
- /* Allocate a new CID for the client to be created */
- if (cid == QMI_CID_NONE) {
- QmiMessageCtlAllocateCidInput *input;
-
- input = qmi_message_ctl_allocate_cid_input_new ();
- qmi_message_ctl_allocate_cid_input_set_service (input, ctx->service, NULL);
-
- g_debug ("[%s] Allocating new client ID...",
- qmi_file_get_path_display (self->priv->file));
- qmi_client_ctl_allocate_cid (self->priv->client_ctl,
- input,
- timeout,
- cancellable,
- (GAsyncReadyCallback)allocate_cid_ready,
- task);
-
- qmi_message_ctl_allocate_cid_input_unref (input);
- return;
- }
-
- /* Reuse the given CID */
- g_debug ("[%s] Reusing client CID '%u'...",
- qmi_file_get_path_display (self->priv->file),
- cid);
- ctx->cid = cid;
- build_client_object (task);
-}
-
-/*****************************************************************************/
-/* Release client */
-
-gboolean
-qmi_device_release_client_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void
-client_ctl_release_cid_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
- QmiMessageCtlReleaseCidOutput *output;
-
- /* Note: even if we return an error, the client is to be considered
- * released! (so shouldn't be used) */
-
- /* Check result of the async operation */
- output = qmi_client_ctl_release_cid_finish (client_ctl, res, &error);
- if (!output) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_release_cid_output_get_result (output, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- qmi_message_ctl_release_cid_output_unref (output);
- return;
- }
-
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- qmi_message_ctl_release_cid_output_unref (output);
-}
-
-void
-qmi_device_release_client (QmiDevice *self,
- QmiClient *client,
- QmiDeviceReleaseClientFlags flags,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- QmiService service;
- guint8 cid;
- gchar *flags_str;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (QMI_IS_CLIENT (client));
-
- cid = qmi_client_get_cid (client);
- service = (guint8)qmi_client_get_service (client);
-
- /* The CTL client should not have been created out of the QmiDevice */
- g_return_if_fail (service != QMI_SERVICE_CTL);
-
- flags_str = qmi_device_release_client_flags_build_string_from_mask (flags);
- g_debug ("[%s] Releasing '%s' client with flags '%s'...",
- qmi_file_get_path_display (self->priv->file),
- qmi_service_get_string (service),
- flags_str);
- g_free (flags_str);
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- /* Do not try to release an already released client */
- if (cid == QMI_CID_NONE) {
- g_task_return_new_error (task,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_INVALID_ARGS,
- "Client is already released");
- g_object_unref (task);
- return;
- }
-
- /* Keep the client object valid until after we reset its contents below */
- g_object_ref (client);
-
- /* Unregister from device */
- unregister_client (self, client);
-
- g_debug ("[%s] Unregistered '%s' client with ID '%u'",
- qmi_file_get_path_display (self->priv->file),
- qmi_service_get_string (service),
- cid);
-
- /* Reset the contents of the client object, making it invalid */
- g_object_set (client,
- QMI_CLIENT_CID, QMI_CID_NONE,
- QMI_CLIENT_SERVICE, QMI_SERVICE_UNKNOWN,
- QMI_CLIENT_DEVICE, NULL,
- NULL);
-
- g_object_unref (client);
-
- if (flags & QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID) {
- QmiMessageCtlReleaseCidInput *input;
-
- /* And now, really try to release the CID */
- input = qmi_message_ctl_release_cid_input_new ();
- qmi_message_ctl_release_cid_input_set_release_info (input, service, cid, NULL);
-
- qmi_client_ctl_release_cid (self->priv->client_ctl,
- input,
- timeout,
- cancellable,
- (GAsyncReadyCallback)client_ctl_release_cid_ready,
- task);
-
- qmi_message_ctl_release_cid_input_unref (input);
- return;
- }
-
- /* No need to release the CID, so just done */
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
-}
-
-/*****************************************************************************/
-/* Set instance ID */
-
-gboolean
-qmi_device_set_instance_id_finish (QmiDevice *self,
- GAsyncResult *res,
- guint16 *link_id,
- GError **error)
-{
- gssize value;
-
- value = g_task_propagate_int (G_TASK (res), error);
- if (value == -1)
- return FALSE;
-
- if (link_id)
- *link_id = (guint16)value;
-
- return TRUE;
-}
-
-static void
-set_instance_id_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- QmiMessageCtlSetInstanceIdOutput *output;
- GError *error = NULL;
-
- /* Check result of the async operation */
- output = qmi_client_ctl_set_instance_id_finish (client_ctl, res, &error);
- if (!output)
- g_task_return_error (task, error);
- else {
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_set_instance_id_output_get_result (output, &error))
- g_task_return_error (task, error);
- else {
- guint16 link_id;
-
- qmi_message_ctl_set_instance_id_output_get_link_id (output, &link_id, NULL);
- g_task_return_int (task, link_id);
- }
- qmi_message_ctl_set_instance_id_output_unref (output);
- }
-
- g_object_unref (task);
-}
-
-void
-qmi_device_set_instance_id (QmiDevice *self,
- guint8 instance_id,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- QmiMessageCtlSetInstanceIdInput *input;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- input = qmi_message_ctl_set_instance_id_input_new ();
- qmi_message_ctl_set_instance_id_input_set_id (
- input,
- instance_id,
- NULL);
- qmi_client_ctl_set_instance_id (self->priv->client_ctl,
- input,
- timeout,
- cancellable,
- (GAsyncReadyCallback)set_instance_id_ready,
- task);
- qmi_message_ctl_set_instance_id_input_unref (input);
-}
-
-/*****************************************************************************/
-/* Input channel processing */
-
-static void process_message (QmiMessage *message, QmiDevice *self);
-
-static void
-endpoint_new_data_cb (QmiEndpoint *endpoint,
- QmiDevice *self)
-{
- GError *error = NULL;
-
- if (!qmi_endpoint_parse_buffer (endpoint,
- (QmiMessageHandler)process_message,
- self,
- &error)) {
- g_warning ("[%s] QMI parsing error: %s",
- qmi_file_get_path_display (self->priv->file), error->message);
- g_error_free (error);
- }
-}
-
-static void
-endpoint_hangup_cb (QmiEndpoint *endpoint,
- QmiDevice *self)
-{
- g_debug ("[%s] QMI endpoint hangup: removed",
- qmi_file_get_path_display (self->priv->file));
-
- /* cancel all ongoing transactions as the endpoing hangup happened */
- device_hangup_transactions (self);
-
- g_signal_emit (self, signals[SIGNAL_REMOVED], 0);
-}
-
-typedef struct {
- QmiClient *client;
- QmiMessage *message;
-} IdleIndicationContext;
-
-static gboolean
-process_indication_idle (IdleIndicationContext *ctx)
-{
- g_assert (ctx->client != NULL);
- g_assert (ctx->message != NULL);
-
- __qmi_client_process_indication (ctx->client, ctx->message);
-
- g_object_unref (ctx->client);
- qmi_message_unref (ctx->message);
- g_slice_free (IdleIndicationContext, ctx);
- return FALSE;
-}
-
-static void
-report_indication (QmiClient *client,
- QmiMessage *message)
-{
- IdleIndicationContext *ctx;
- GSource *source;
-
- /* Setup an idle to Pass the indication down to the client */
- ctx = g_slice_new (IdleIndicationContext);
- ctx->client = g_object_ref (client);
- ctx->message = qmi_message_ref (message);
-
- source = g_idle_source_new ();
- g_source_set_callback (source, (GSourceFunc)process_indication_idle, ctx, NULL);
- g_source_attach (source, g_main_context_get_thread_default ());
- g_source_unref (source);
-}
-
-static void
-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;
-
- if (sent_or_received) {
- prefix_str = "<<<<<< ";
- action_str = "Sent";
- } else {
- prefix_str = "<<<<<< ";
- action_str = "Received";
- }
-
- printable = qmi_helpers_str_hex (((GByteArray *)message)->data,
- ((GByteArray *)message)->len,
- ':');
- g_debug ("[%s] %s message...\n"
- "%sRAW:\n"
- "%s length = %u\n"
- "%s data = %s\n",
- qmi_file_get_path_display (self->priv->file), 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",
- qmi_file_get_path_display (self->priv->file),
- action_str,
- vendor_str ? vendor_str : "generic",
- message_str,
- printable);
- g_free (printable);
-
- g_free (vendor_str);
-}
-
-static void
-process_message (QmiMessage *message,
- QmiDevice *self)
-{
- 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);
-
- if (qmi_message_get_client_id (message) == QMI_CID_BROADCAST) {
- GHashTableIter iter;
- gpointer key;
- QmiClient *client;
-
- g_hash_table_iter_init (&iter, self->priv->registered_clients);
- while (g_hash_table_iter_next (&iter, &key, (gpointer *)&client)) {
- /* For broadcast messages, report them just if the service matches */
- if (qmi_message_get_service (message) == qmi_client_get_service (client))
- report_indication (client, message);
- }
- } else {
- QmiClient *client;
-
- client = g_hash_table_lookup (self->priv->registered_clients,
- build_registered_client_key (qmi_message_get_client_id (message),
- qmi_message_get_service (message)));
- if (client)
- report_indication (client, message);
- }
-
- return;
- }
-
- if (qmi_message_is_response (message)) {
- Transaction *tr;
-
- tr = device_match_transaction (self, message);
- 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",
- qmi_file_get_path_display (self->priv->file));
- return;
- }
-
- /* Did the transaction sequence get out of sync? e.g. if the module reboots itself
- * while we're talking to it. If so, fail the transaction right away without setting the
- * message as response, or otherwise the parsers will complain */
- if (qmi_message_get_message_id (tr->message) != qmi_message_get_message_id (message)) {
- g_autoptr(GError) error = NULL;
-
- error = g_error_new (QMI_CORE_ERROR,
- QMI_CORE_ERROR_UNEXPECTED_MESSAGE,
- "Unexpected response of type 0x%04x received matching transaction for request of type 0x%04x",
- qmi_message_get_message_id (message),
- qmi_message_get_message_id (tr->message));
-
- /* Translate without an explicit context as this message has nothing to do with the
- * request. */
- trace_message (self, message, FALSE, "response", NULL);
- g_debug ("[%s] Mismatched message id in received message for transaction 0x%04x (expected 0x%04x, received 0x%04x)",
- qmi_file_get_path_display (self->priv->file),
- qmi_message_get_transaction_id (message),
- qmi_message_get_message_id (tr->message),
- qmi_message_get_message_id (message));
- transaction_complete_and_free (tr, NULL, error);
- return;
- }
-
- /* 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.",
- qmi_file_get_path_display (self->priv->file));
-}
-
-/*****************************************************************************/
-
-static gboolean
-setup_net_port_manager (QmiDevice *self,
- GError **error)
-{
- QmiDeviceExpectedDataFormat expected_data_format;
-
- /* If we have a valid one already, use that one */
- if (self->priv->net_port_manager)
- return TRUE;
-
- /* The qmi_wwan driver allows configuring the expected data format,
- * and depending on the configured one, we'll use one link management
- * api or another one. */
- expected_data_format = qmi_device_get_expected_data_format (self, NULL);
-
- switch (expected_data_format) {
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_802_3:
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Link management not supported with the expected data format configured as 802.3");
- break;
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_RAW_IP:
- self->priv->net_port_manager = QMI_NET_PORT_MANAGER (qmi_net_port_manager_qmiwwan_new (self->priv->wwan_iface, error));
- break;
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_QMAP_PASS_THROUGH:
- case QMI_DEVICE_EXPECTED_DATA_FORMAT_UNKNOWN:
- default:
-#if defined RMNET_SUPPORT_ENABLED
- /* when the data format is unknown, it very likely is because this
- * is not the qmi_wwan driver; fallback to plain rmnet in that
- * case. */
- self->priv->net_port_manager = QMI_NET_PORT_MANAGER (qmi_net_port_manager_rmnet_new (error));
-#else
- g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Link management not supported");
-#endif
- break;
- }
-
- return !!self->priv->net_port_manager;
-}
-
-/*****************************************************************************/
-/* Link management APIs */
-
-typedef struct {
- guint mux_id;
- gchar *ifname;
-} AddLinkResult;
-
-static void
-add_link_result_free (AddLinkResult *ctx)
-{
- g_free (ctx->ifname);
- g_free (ctx);
-}
-
-gchar *
-qmi_device_add_link_with_flags_finish (QmiDevice *self,
- GAsyncResult *res,
- guint *mux_id,
- GError **error)
-{
- AddLinkResult *ctx;
- gchar *ifname;
-
- ctx = g_task_propagate_pointer (G_TASK (res), error);
- if (!ctx)
- return NULL;
-
- if (mux_id)
- *mux_id = ctx->mux_id;
-
- ifname = g_steal_pointer (&ctx->ifname);
- add_link_result_free (ctx);
- return ifname;
-}
-
-gchar *
-qmi_device_add_link_finish (QmiDevice *self,
- GAsyncResult *res,
- guint *mux_id,
- GError **error)
-{
- return qmi_device_add_link_with_flags_finish (self, res, mux_id, error);
-}
-
-static void
-device_add_link_ready (QmiNetPortManager *net_port_manager,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
- AddLinkResult *ctx;
-
- ctx = g_new0 (AddLinkResult, 1);
- ctx->ifname = qmi_net_port_manager_add_link_finish (net_port_manager, &ctx->mux_id, res, &error);
-
- if (!ctx->ifname) {
- g_prefix_error (&error, "Could not allocate link: ");
- g_task_return_error (task, error);
- add_link_result_free (ctx);
- } else
- g_task_return_pointer (task, ctx, (GDestroyNotify) add_link_result_free);
-
- g_object_unref (task);
-}
-
-void
-qmi_device_add_link_with_flags (QmiDevice *self,
- guint mux_id,
- const gchar *base_ifname,
- const gchar *ifname_prefix,
- QmiDeviceAddLinkFlags flags,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- GError *error = NULL;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (base_ifname);
- g_return_if_fail (mux_id >= QMI_DEVICE_MUX_ID_MIN);
- g_return_if_fail ((mux_id <= QMI_DEVICE_MUX_ID_MAX) || (mux_id == QMI_DEVICE_MUX_ID_AUTOMATIC));
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- if (!setup_net_port_manager (self, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- g_assert (self->priv->net_port_manager);
- qmi_net_port_manager_add_link (self->priv->net_port_manager,
- mux_id,
- base_ifname,
- ifname_prefix,
- flags,
- 5,
- cancellable,
- (GAsyncReadyCallback) device_add_link_ready,
- task);
-}
-
-void
-qmi_device_add_link (QmiDevice *self,
- guint mux_id,
- const gchar *base_ifname,
- const gchar *ifname_prefix,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- qmi_device_add_link_with_flags (self, mux_id, base_ifname, ifname_prefix,
- QMI_DEVICE_ADD_LINK_FLAGS_NONE,
- cancellable, callback, user_data);
-}
-
-gboolean
-qmi_device_delete_link_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void
-device_del_link_ready (QmiNetPortManager *net_port_manager,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
-
- if (!qmi_net_port_manager_del_link_finish (net_port_manager, res, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-void
-qmi_device_delete_link (QmiDevice *self,
- const gchar *ifname,
- guint mux_id,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- GError *error = NULL;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (ifname);
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- if (!setup_net_port_manager (self, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- g_assert (self->priv->net_port_manager);
- qmi_net_port_manager_del_link (self->priv->net_port_manager,
- ifname,
- mux_id,
- 5, /* timeout */
- cancellable,
- (GAsyncReadyCallback) device_del_link_ready,
- task);
-}
-
-/*****************************************************************************/
-
-gboolean
-qmi_device_delete_all_links_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void
-device_del_all_links_ready (QmiNetPortManager *net_port_manager,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
-
- if (!qmi_net_port_manager_del_all_links_finish (net_port_manager, res, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-void
-qmi_device_delete_all_links (QmiDevice *self,
- const gchar *base_ifname,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- GError *error = NULL;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (base_ifname);
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- if (!setup_net_port_manager (self, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- g_assert (self->priv->net_port_manager);
- qmi_net_port_manager_del_all_links (self->priv->net_port_manager,
- base_ifname,
- cancellable,
- (GAsyncReadyCallback) device_del_all_links_ready,
- task);
-}
-
-/*****************************************************************************/
-
-gboolean
-qmi_device_list_links (QmiDevice *self,
- const gchar *base_ifname,
- GPtrArray **out_links,
- GError **error)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), FALSE);
- g_return_val_if_fail (base_ifname, FALSE);
-
- if (!setup_net_port_manager (self, error))
- return FALSE;
-
- g_assert (self->priv->net_port_manager);
- return qmi_net_port_manager_list_links (self->priv->net_port_manager,
- base_ifname,
- out_links,
- error);
-}
-
-/*****************************************************************************/
-
-gboolean
-qmi_device_check_link_supported (QmiDevice *self,
- GError **error)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), FALSE);
-
- /* if we can setup a net port manager, link management is supported */
- return setup_net_port_manager (self, error);
-}
-
-/*****************************************************************************/
-/* Open device */
-
-#define SYNC_TIMEOUT_SECS 2
-
-typedef enum {
- DEVICE_OPEN_CONTEXT_STEP_FIRST = 0,
- DEVICE_OPEN_CONTEXT_STEP_DRIVER,
- DEVICE_OPEN_CONTEXT_STEP_CREATE_ENDPOINT,
- DEVICE_OPEN_CONTEXT_STEP_OPEN_ENDPOINT,
- DEVICE_OPEN_CONTEXT_STEP_FLAGS_VERSION_INFO,
- DEVICE_OPEN_CONTEXT_STEP_FLAGS_SYNC,
- DEVICE_OPEN_CONTEXT_STEP_FLAGS_NETPORT,
- DEVICE_OPEN_CONTEXT_STEP_FLAGS_EXPECT_INDICATIONS,
- DEVICE_OPEN_CONTEXT_STEP_LAST
-} DeviceOpenContextStep;
-
-typedef struct {
- DeviceOpenContextStep step;
- QmiDeviceOpenFlags flags;
- guint timeout;
- guint version_check_retries;
- guint sync_retries;
-} DeviceOpenContext;
-
-static void
-device_open_context_free (DeviceOpenContext *ctx)
-{
- g_slice_free (DeviceOpenContext, ctx);
-}
-
-gboolean
-qmi_device_open_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void device_open_step (GTask *task);
-
-static void
-setup_indications_ready (QmiEndpoint *endpoint,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
- DeviceOpenContext *ctx;
-
- ctx = g_task_get_task_data (task);
-
- if (!qmi_endpoint_setup_indications_finish (endpoint, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- ctx->step++;
- device_open_step (task);
-}
-
-static void
-ctl_set_data_format_ready (QmiClientCtl *client,
- GAsyncResult *res,
- GTask *task)
-{
- QmiDevice *self;
- DeviceOpenContext *ctx;
- QmiMessageCtlSetDataFormatOutput *output = NULL;
- GError *error = NULL;
-
- output = qmi_client_ctl_set_data_format_finish (client, res, &error);
- /* Check result of the async operation */
- if (!output) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_set_data_format_output_get_result (output, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- qmi_message_ctl_set_data_format_output_unref (output);
- return;
- }
-
- self = g_task_get_source_object (task);
-
- g_debug ("[%s] Network port data format operation finished",
- qmi_file_get_path_display (self->priv->file));
-
- qmi_message_ctl_set_data_format_output_unref (output);
-
- /* Go on */
- ctx = g_task_get_task_data (task);
- ctx->step++;
- device_open_step (task);
-}
-
-static void
-sync_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- QmiDevice *self;
- DeviceOpenContext *ctx;
- GError *error = NULL;
- QmiMessageCtlSyncOutput *output;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* Check result of the async operation */
- output = qmi_client_ctl_sync_finish (client_ctl, res, &error);
- if (!output) {
- if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT)) {
- /* Update retries... */
- ctx->sync_retries--;
- /* If retries left, retry */
- if (ctx->sync_retries > 0) {
- g_error_free (error);
- qmi_client_ctl_sync (self->priv->client_ctl,
- NULL,
- SYNC_TIMEOUT_SECS,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)sync_ready,
- task);
- return;
- }
-
- /* Otherwise, propagate the error */
- }
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_sync_output_get_result (output, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- qmi_message_ctl_sync_output_unref (output);
- return;
- }
-
- g_debug ("[%s] Sync operation finished",
- qmi_file_get_path_display (self->priv->file));
-
- qmi_message_ctl_sync_output_unref (output);
-
- /* Go on */
- ctx->step++;
- device_open_step (task);
-}
-
-static void
-open_version_info_ready (QmiClientCtl *client_ctl,
- GAsyncResult *res,
- GTask *task)
-{
- QmiDevice *self;
- DeviceOpenContext *ctx;
- GArray *service_list;
- QmiMessageCtlGetVersionInfoOutput *output;
- GError *error = NULL;
- guint i;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* Check result of the async operation */
- output = qmi_client_ctl_get_version_info_finish (client_ctl, res, &error);
- if (!output) {
- if (g_error_matches (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT)) {
- /* Update retries... */
- ctx->version_check_retries--;
- /* If retries left, retry */
- if (ctx->version_check_retries > 0) {
- g_error_free (error);
- qmi_client_ctl_get_version_info (self->priv->client_ctl,
- NULL,
- 1,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)open_version_info_ready,
- task);
- return;
- }
-
- /* Otherwise, propagate the error */
- }
-
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Check result of the QMI operation */
- if (!qmi_message_ctl_get_version_info_output_get_result (output, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- qmi_message_ctl_get_version_info_output_unref (output);
- return;
- }
-
- /* QMI operation succeeded, we can now get the outputs */
- service_list = NULL;
- qmi_message_ctl_get_version_info_output_get_service_list (output,
- &service_list,
- NULL);
-
- g_clear_pointer (&self->priv->supported_services, g_array_unref);
- self->priv->supported_services = g_array_ref (service_list);
-
- g_debug ("[%s] QMI Device supports %u services:",
- qmi_file_get_path_display (self->priv->file),
- self->priv->supported_services->len);
- for (i = 0; i < self->priv->supported_services->len; i++) {
- QmiMessageCtlGetVersionInfoOutputServiceListService *info;
- const gchar *service_str;
-
- info = &g_array_index (self->priv->supported_services,
- QmiMessageCtlGetVersionInfoOutputServiceListService,
- i);
- service_str = qmi_service_get_string (info->service);
- if (service_str)
- g_debug ("[%s] %s (%u.%u)",
- qmi_file_get_path_display (self->priv->file),
- service_str,
- info->major_version,
- info->minor_version);
- else
- g_debug ("[%s] unknown [0x%02x] (%u.%u)",
- qmi_file_get_path_display (self->priv->file),
- info->service,
- info->major_version,
- info->minor_version);
- }
-
- qmi_message_ctl_get_version_info_output_unref (output);
-
- /* Go on */
- ctx->step++;
- device_open_step (task);
-}
-
-#if QMI_QRTR_SUPPORTED
-
-static void
-build_services_from_qrtr_node (GTask *task)
-{
- QmiDevice *self;
- DeviceOpenContext *ctx;
- GList *services;
- guint n_services;
- GList *elem;
- QrtrNodeServiceInfo *qrtr_serv_info;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- g_assert (self->priv->node);
- services = qrtr_node_peek_service_info_list (self->priv->node);
- n_services = g_list_length (services);
-
- g_clear_pointer (&self->priv->supported_services, g_array_unref);
- self->priv->supported_services = g_array_sized_new (FALSE,
- FALSE,
- sizeof (QmiMessageCtlGetVersionInfoOutputServiceListService),
- n_services);
-
- g_debug ("[%s] QMI Device supports %u services:",
- qmi_file_get_path_display (self->priv->file),
- n_services);
-
- for (elem = services; elem; elem = elem->next) {
- const gchar *service_str;
- QmiMessageCtlGetVersionInfoOutputServiceListService info;
-
- qrtr_serv_info = elem->data;
- info.service = qrtr_node_service_info_get_service (qrtr_serv_info);
- info.major_version = qrtr_node_service_info_get_version (qrtr_serv_info);
- g_array_append_val (self->priv->supported_services, info);
-
- service_str = qmi_service_get_string (info.service);
- if (service_str)
- g_debug ("[%s] %s (%u) ",
- qmi_file_get_path_display (self->priv->file),
- service_str,
- info.major_version);
- else
- g_debug ("[%s] unknown [0x%04x] (%u)",
- qmi_file_get_path_display (self->priv->file),
- info.service,
- info.major_version);
- }
-
- ctx->step++;
- device_open_step (task);
-}
-#endif
-
-static void
-endpoint_ready (QmiEndpoint *endpoint,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
- DeviceOpenContext *ctx;
-
- ctx = g_task_get_task_data (task);
-
- if (!qmi_endpoint_open_finish (endpoint, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- ctx->step++;
- device_open_step (task);
-}
-
-#define NETPORT_FLAGS (QMI_DEVICE_OPEN_FLAGS_NET_802_3 | \
- QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP | \
- QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER | \
- QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER)
-
-static void
-device_create_endpoint (QmiDevice *self,
- DeviceOpenContext *ctx)
-{
- if (!(ctx->flags & QMI_DEVICE_OPEN_FLAGS_MBIM)) {
-#if QMI_QRTR_SUPPORTED
- /* We talk to proxies over QMUX even if they are proxying a QRTR device. */
- if (self->priv->node && !(ctx->flags & QMI_DEVICE_OPEN_FLAGS_PROXY)) {
- self->priv->endpoint = QMI_ENDPOINT (qmi_endpoint_qrtr_new (self->priv->node));
- } else
-#endif
- {
- self->priv->endpoint = QMI_ENDPOINT (qmi_endpoint_qmux_new (self->priv->file,
- self->priv->proxy_path,
- self->priv->client_ctl));
- }
- }
-#if defined MBIM_QMUX_ENABLED
- else {
- self->priv->endpoint = QMI_ENDPOINT (qmi_endpoint_mbim_new (self->priv->file));
- }
-#endif /* MBIM_QMUX_ENABLED */
-
- if (!self->priv->endpoint)
- return;
-
- self->priv->endpoint_new_data_id = g_signal_connect (self->priv->endpoint,
- QMI_ENDPOINT_SIGNAL_NEW_DATA,
- G_CALLBACK (endpoint_new_data_cb),
- self);
- self->priv->endpoint_hangup_id = g_signal_connect (self->priv->endpoint,
- QMI_ENDPOINT_SIGNAL_HANGUP,
- G_CALLBACK (endpoint_hangup_cb),
- self);
- g_debug ("[%s] created endpoint", qmi_file_get_path_display (self->priv->file));
-}
-
-static gboolean
-device_setup_open_flags_by_transport (QmiDevice *self,
- DeviceOpenContext *ctx,
- GError **error)
-{
- QmiHelpersTransportType transport;
- GError *inner_error = NULL;
-
- transport = qmi_helpers_get_transport_type (qmi_file_get_path (self->priv->file), &inner_error);
- if ((transport == QMI_HELPERS_TRANSPORT_TYPE_UNKNOWN) && !self->priv->no_file_check)
- g_warning ("[%s] couldn't detect transport type of port: %s", qmi_file_get_path_display (self->priv->file), inner_error->message);
- g_clear_error (&inner_error);
-
-#if defined MBIM_QMUX_ENABLED
-
- /* Auto mode requested? */
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_AUTO) {
- switch (transport) {
- case QMI_HELPERS_TRANSPORT_TYPE_MBIM:
- g_debug ("[%s] automatically selecting MBIM mode", qmi_file_get_path_display (self->priv->file));
- ctx->flags |= QMI_DEVICE_OPEN_FLAGS_MBIM;
- break;
- case QMI_HELPERS_TRANSPORT_TYPE_QMUX:
- g_debug ("[%s] automatically selecting QMI mode", qmi_file_get_path_display (self->priv->file));
- ctx->flags &= ~QMI_DEVICE_OPEN_FLAGS_MBIM;
- break;
- case QMI_HELPERS_TRANSPORT_TYPE_UNKNOWN:
- g_set_error (&inner_error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "Cannot automatically select QMI/MBIM mode");
- break;
- default:
- g_assert_not_reached ();
- }
- goto out;
- }
-
- /* MBIM mode requested? */
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_MBIM) {
- if ((transport != QMI_HELPERS_TRANSPORT_TYPE_MBIM) && !self->priv->no_file_check)
- g_warning ("[%s] requested MBIM mode but unexpected transport type found", qmi_file_get_path_display (self->priv->file));
- goto out;
- }
-
-#else
-
- /* MBIM mode requested? */
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_MBIM) {
- g_warning ("[%s] requested MBIM mode but no MBIM QMUX support available", qmi_file_get_path_display (self->priv->file));
- goto out;
- }
-
- /* Treat AUTO as QMI mode, without warnings */
-
-#endif /* MBIM_QMUX_ENABLED */
-
- /* QMI mode requested? */
- if ((transport != QMI_HELPERS_TRANSPORT_TYPE_QMUX) && !self->priv->no_file_check)
- g_warning ("[%s] requested QMI mode but unexpected transport type found",
- qmi_file_get_path_display (self->priv->file));
-
-out:
-
- if (inner_error) {
- g_propagate_error (error, inner_error);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-device_open_step (GTask *task)
-{
- QmiDevice *self;
- DeviceOpenContext *ctx;
- GError *error = NULL;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- switch (ctx->step) {
- case DEVICE_OPEN_CONTEXT_STEP_FIRST:
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_DRIVER:
-#if QMI_QRTR_SUPPORTED
- if (self->priv->node) {
- g_debug ("[%s] selecting QMI mode for QRTR endpoint",
- qmi_file_get_path_display (self->priv->file));
- ctx->flags &= ~QMI_DEVICE_OPEN_FLAGS_MBIM;
- } else
-#endif
- if (!device_setup_open_flags_by_transport (self, ctx, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_CREATE_ENDPOINT:
- device_create_endpoint (self, ctx);
- if (!self->priv->endpoint) {
- g_task_return_new_error (task,
- QMI_CORE_ERROR,
- QMI_CORE_ERROR_FAILED,
- "Could not create endpoint");
- g_object_unref (task);
- return;
- }
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_OPEN_ENDPOINT:
- qmi_endpoint_open (self->priv->endpoint,
- !!(ctx->flags & QMI_DEVICE_OPEN_FLAGS_PROXY),
- 5,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)endpoint_ready,
- task);
- return;
-
- case DEVICE_OPEN_CONTEXT_STEP_FLAGS_VERSION_INFO:
- /* Query version info? */
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_VERSION_INFO) {
- /* Setup how many times to retry... We'll retry once per second */
- ctx->version_check_retries = ctx->timeout > 0 ? ctx->timeout : 1;
- g_debug ("[%s] Checking version info (%u retries)...",
- qmi_file_get_path_display (self->priv->file),
- ctx->version_check_retries);
-#if QMI_QRTR_SUPPORTED
- if (self->priv->node) {
- g_debug ("[%s] QRTR does not support version info check: checking only for available services",
- qmi_file_get_path_display (self->priv->file));
- build_services_from_qrtr_node (task);
- }
- else
-#endif
- qmi_client_ctl_get_version_info (self->priv->client_ctl,
- NULL,
- 1,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)open_version_info_ready,
- task);
-
- return;
- }
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_FLAGS_SYNC:
- /* Sync? */
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_SYNC) {
- /* Setup how many times to retry... We'll retry once per second */
- ctx->sync_retries = ctx->timeout > SYNC_TIMEOUT_SECS ? (ctx->timeout / SYNC_TIMEOUT_SECS) : 1;
- g_debug ("[%s] Running sync (%u retries)...",
- qmi_file_get_path_display (self->priv->file),
- ctx->sync_retries);
- qmi_client_ctl_sync (self->priv->client_ctl,
- NULL,
- SYNC_TIMEOUT_SECS,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)sync_ready,
- task);
- return;
- }
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_FLAGS_NETPORT:
- /* Network port setup */
- if (ctx->flags & NETPORT_FLAGS) {
- QmiMessageCtlSetDataFormatInput *input;
- QmiCtlDataFormat qos = QMI_CTL_DATA_FORMAT_QOS_FLOW_HEADER_ABSENT;
- QmiCtlDataLinkProtocol link_protocol = QMI_CTL_DATA_LINK_PROTOCOL_802_3;
-
- g_debug ("[%s] Setting network port data format...",
- qmi_file_get_path_display (self->priv->file));
-
- input = qmi_message_ctl_set_data_format_input_new ();
-
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER)
- qos = QMI_CTL_DATA_FORMAT_QOS_FLOW_HEADER_PRESENT;
- qmi_message_ctl_set_data_format_input_set_format (input, qos, NULL);
-
- if (ctx->flags & QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP)
- link_protocol = QMI_CTL_DATA_LINK_PROTOCOL_RAW_IP;
- qmi_message_ctl_set_data_format_input_set_protocol (input, link_protocol, NULL);
-
- qmi_client_ctl_set_data_format (self->priv->client_ctl,
- input,
- 5,
- NULL,
- (GAsyncReadyCallback)ctl_set_data_format_ready,
- task);
- qmi_message_ctl_set_data_format_input_unref (input);
- return;
- }
- ctx->step++;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_FLAGS_EXPECT_INDICATIONS:
- qmi_endpoint_setup_indications (self->priv->endpoint,
- 10,
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)setup_indications_ready,
- task);
- return;
- /* Fall through */
-
- case DEVICE_OPEN_CONTEXT_STEP_LAST:
- /* Nothing else to process, done we are */
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
-
- default:
- break;
- }
-
- g_assert_not_reached ();
-}
-
-void
-qmi_device_open (QmiDevice *self,
- QmiDeviceOpenFlags flags,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- DeviceOpenContext *ctx;
- gchar *flags_str;
- GTask *task;
-
- /* Raw IP and 802.3 are mutually exclusive */
- g_return_if_fail (!((flags & QMI_DEVICE_OPEN_FLAGS_NET_802_3) &&
- (flags & QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP)));
- /* QoS and no QoS are mutually exclusive */
- g_return_if_fail (!((flags & QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER) &&
- (flags & QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER)));
- /* At least one of both link protocol and QoS must be specified */
- if (flags & (QMI_DEVICE_OPEN_FLAGS_NET_802_3 | QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP))
- g_return_if_fail (flags & (QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER | QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER));
- if (flags & (QMI_DEVICE_OPEN_FLAGS_NET_QOS_HEADER | QMI_DEVICE_OPEN_FLAGS_NET_NO_QOS_HEADER))
- g_return_if_fail (flags & (QMI_DEVICE_OPEN_FLAGS_NET_802_3 | QMI_DEVICE_OPEN_FLAGS_NET_RAW_IP));
-
- g_return_if_fail (QMI_IS_DEVICE (self));
-
- flags_str = qmi_device_open_flags_build_string_from_mask (flags);
- g_debug ("[%s] Opening device with flags '%s'...",
- qmi_file_get_path_display (self->priv->file),
- flags_str);
- g_free (flags_str);
-
- ctx = g_slice_new (DeviceOpenContext);
- ctx->step = DEVICE_OPEN_CONTEXT_STEP_FIRST;
- ctx->flags = flags;
- ctx->timeout = timeout;
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_task_data (task, ctx, (GDestroyNotify)device_open_context_free);
-
- /* Start processing */
- device_open_step (task);
-}
-
-/*****************************************************************************/
-/* Close stream */
-
-typedef struct {
- QmiEndpoint *endpoint;
- guint endpoint_new_data_id;
- guint endpoint_hangup_id;
-} CloseContext;
-
-static void
-close_context_free (CloseContext *ctx)
-{
- if (ctx->endpoint_hangup_id)
- g_signal_handler_disconnect (ctx->endpoint, ctx->endpoint_hangup_id);
- if (ctx->endpoint_new_data_id)
- g_signal_handler_disconnect (ctx->endpoint, ctx->endpoint_new_data_id);
- g_object_unref (ctx->endpoint);
- g_slice_free (CloseContext, ctx);
-}
-
-gboolean
-qmi_device_close_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void
-endpoint_close_ready (QmiEndpoint *endpoint,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
-
- if (!qmi_endpoint_close_finish (endpoint, res, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-void
-qmi_device_close_async (QmiDevice *self,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- CloseContext *ctx;
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- /* if already closed, we're done */
- if (!self->priv->endpoint) {
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- /* Steal endpoint setup from private info, it will be freed once
- * the task is completed and disposed */
- ctx = g_slice_new0 (CloseContext);
- ctx->endpoint = g_steal_pointer (&self->priv->endpoint);
- ctx->endpoint_new_data_id = self->priv->endpoint_new_data_id;
- self->priv->endpoint_new_data_id = 0;
- ctx->endpoint_hangup_id = self->priv->endpoint_hangup_id;
- self->priv->endpoint_hangup_id = 0;
- g_task_set_task_data (task, ctx, (GDestroyNotify) close_context_free);
-
- qmi_endpoint_close (ctx->endpoint,
- timeout,
- cancellable,
- (GAsyncReadyCallback)endpoint_close_ready,
- task);
-}
-
-/*****************************************************************************/
-/* Command */
-
-QmiMessage *
-qmi_device_command_abortable_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
- return NULL;
-
- return qmi_message_ref (g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (res)));
-}
-
-static void
-transaction_early_error (QmiDevice *self,
- Transaction *tr,
- gboolean stored,
- GError *error)
-{
- g_assert (error);
-
- if (stored) {
- /* Match transaction so that we remove it from our tracking table */
- tr = device_match_transaction (self, tr->message);
- g_assert (tr);
- }
- transaction_complete_and_free (tr, NULL, error);
- g_error_free (error);
-}
-
-void
-qmi_device_command_abortable (QmiDevice *self,
- QmiMessage *message,
- QmiMessageContext *message_context,
- guint timeout,
- QmiDeviceCommandAbortableBuildRequestFn abort_build_request_fn,
- QmiDeviceCommandAbortableParseResponseFn abort_parse_response_fn,
- gpointer abort_user_data,
- GDestroyNotify abort_user_data_free,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GError *error = NULL;
- Transaction *tr;
-
- g_return_if_fail (QMI_IS_DEVICE (self));
- g_return_if_fail (message != NULL);
- g_return_if_fail (timeout > 0);
-
- /* either none or both set */
- g_return_if_fail ((!abort_build_request_fn && !abort_parse_response_fn) ||
- (abort_build_request_fn && abort_parse_response_fn));
-
- /* Use a proper transaction id for CTL messages if they don't have one */
- if (qmi_message_get_service (message) == QMI_SERVICE_CTL &&
- qmi_message_get_transaction_id (message) == 0) {
- qmi_message_set_transaction_id (
- message,
- qmi_client_get_next_transaction_id (
- QMI_CLIENT (
- self->priv->client_ctl)));
- }
-
- tr = transaction_new (self, message, message_context, cancellable, callback, user_data);
-
- /* Device must be open */
- if (!qmi_device_is_open (self)) {
- error = g_error_new (QMI_CORE_ERROR,
- QMI_CORE_ERROR_WRONG_STATE,
- "Device must be open to send commands");
- transaction_early_error (self, tr, FALSE, error);
- return;
- }
-
- /* Non-CTL services should use a proper CID */
- if (qmi_message_get_service (message) != QMI_SERVICE_CTL &&
- qmi_message_get_client_id (message) == 0) {
- error = g_error_new (QMI_CORE_ERROR,
- QMI_CORE_ERROR_FAILED,
- "Cannot send message in service '%s' without a CID",
- qmi_service_get_string (qmi_message_get_service (message)));
- transaction_early_error (self, tr, FALSE, error);
- return;
- }
-
- /* If message is not abortable, we should not allow using the abortable() interface */
- if (!__qmi_message_is_abortable (message, message_context)) {
- if (abort_build_request_fn || abort_parse_response_fn) {
- error = g_error_new (QMI_CORE_ERROR,
- QMI_CORE_ERROR_FAILED,
- "Message is not abortable");
- transaction_early_error (self, tr, FALSE, error);
- return;
- }
- } else {
- /* Store abortable info, if any */
- tr->abort_build_request_fn = abort_build_request_fn;
- tr->abort_parse_response_fn = abort_parse_response_fn;
- tr->abort_user_data = abort_user_data;
- tr->abort_user_data_free = abort_user_data_free;
- }
-
- /* Setup context to match response */
- if (!device_store_transaction (self, tr, timeout, &error)) {
- g_prefix_error (&error, "Cannot store transaction: ");
- transaction_early_error (self, tr, FALSE, error);
- return;
- }
-
- /* 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. */
-
- trace_message (self, message, TRUE, "request", message_context);
-
- if (!qmi_endpoint_send (self->priv->endpoint, message, timeout, cancellable, &error)) {
- transaction_early_error (self, tr, TRUE, error);
- return;
- }
-}
-
-/*****************************************************************************/
-/* Non-abortable standard command */
-
-QmiMessage *
-qmi_device_command_full_finish (QmiDevice *self,
- GAsyncResult *res,
- GError **error)
-{
- return qmi_device_command_abortable_finish (self, res, error);
-}
-
-void
-qmi_device_command_full (QmiDevice *self,
- QmiMessage *message,
- QmiMessageContext *message_context,
- guint timeout,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- qmi_device_command_abortable (self,
- message,
- message_context,
- timeout,
- NULL, /* abort_build_request_fn */
- NULL, /* abort_parse_response_fn */
- NULL, /* abort_user_data */
- NULL, /* abort_user_data_free */
- cancellable,
- callback,
- user_data);
-}
-
-/*****************************************************************************/
-/* New QMI device */
-
-static QmiDevice *
-common_device_new_finish (GAsyncResult *res,
- GError **error)
-{
- g_autoptr(GObject) source_object = NULL;
-
- source_object = g_async_result_get_source_object (res);
- return QMI_DEVICE (g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, error));
-}
-
-#if QMI_QRTR_SUPPORTED
-
-QmiDevice *
-qmi_device_new_from_node_finish (GAsyncResult *res,
- GError **error)
-{
- return common_device_new_finish (res, error);
-}
-
-void
-qmi_device_new_from_node (QrtrNode *node,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_return_if_fail (QRTR_IS_NODE (node));
-
- g_async_initable_new_async (QMI_TYPE_DEVICE,
- G_PRIORITY_DEFAULT,
- cancellable,
- callback,
- user_data,
- QMI_DEVICE_NODE, node,
- NULL);
-}
-
-QrtrNode *
-qmi_device_get_node (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return self->priv->node ? g_object_ref (self->priv->node) : NULL;
-}
-
-QrtrNode *
-qmi_device_peek_node (QmiDevice *self)
-{
- g_return_val_if_fail (QMI_IS_DEVICE (self), NULL);
-
- return self->priv->node;
-}
-#endif
-
-QmiDevice *
-qmi_device_new_finish (GAsyncResult *res,
- GError **error)
-{
- return common_device_new_finish (res, error);
-}
-
-void
-qmi_device_new (GFile *file,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_return_if_fail (G_IS_FILE (file));
-
- g_async_initable_new_async (QMI_TYPE_DEVICE,
- G_PRIORITY_DEFAULT,
- cancellable,
- callback,
- user_data,
- QMI_DEVICE_FILE, file,
- NULL);
-}
-
-/*****************************************************************************/
-/* Async init */
-
-static gboolean
-initable_init_finish (GAsyncInitable *initable,
- GAsyncResult *result,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sync_indication_cb (QmiClientCtl *client_ctl,
- QmiDevice *self)
-{
- /* Just log about it */
- g_debug ("[%s] Sync indication received",
- qmi_file_get_path_display (self->priv->file));
-}
-
-static void
-client_ctl_setup (GTask *task)
-{
- QmiDevice *self;
- GError *error = NULL;
-
- self = g_task_get_source_object (task);
-
- /* Create the implicit CTL client */
- self->priv->client_ctl = g_object_new (QMI_TYPE_CLIENT_CTL,
- QMI_CLIENT_DEVICE, self,
- QMI_CLIENT_SERVICE, QMI_SERVICE_CTL,
- QMI_CLIENT_CID, QMI_CID_NONE,
- NULL);
-
- /* Register the CTL client to get indications */
- register_client (self,
- QMI_CLIENT (self->priv->client_ctl),
- &error);
- g_assert_no_error (error);
-
- /* Connect to 'Sync' indications */
- self->priv->sync_indication_id =
- g_signal_connect (self->priv->client_ctl,
- "sync",
- G_CALLBACK (sync_indication_cb),
- self);
-
- /* Done we are */
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
-
-static void
-check_type_async_ready (QmiFile *file,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
-
- if (!qmi_file_check_type_finish (file, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Go on with client CTL setup */
- client_ctl_setup (task);
-}
-
-static void
-initable_init_async (GAsyncInitable *initable,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- QmiDevice *self;
- GTask *task;
-
- self = QMI_DEVICE (initable);
- task = g_task_new (self, cancellable, callback, user_data);
-
- /* We need a proper file to initialize */
- g_assert (QMI_IS_FILE (self->priv->file));
-
-#if QMI_QRTR_SUPPORTED
- /* If we have a node, just skip to setting up the control client */
- if (self->priv->node) {
- client_ctl_setup (task);
- return;
- }
-#endif
-
- /* If no file check requested, don't do it */
- if (self->priv->no_file_check) {
- client_ctl_setup (task);
- return;
- }
-
- /* Check the file type. Note that this is just a quick check to avoid
- * creating QmiDevices pointing to a location already known not to be a QMI
- * device. */
- qmi_file_check_type_async (self->priv->file,
- cancellable,
- (GAsyncReadyCallback)check_type_async_ready,
- task);
-}
-
-/*****************************************************************************/
-
-#if QMI_QRTR_SUPPORTED
-static QmiFile *
-get_file_for_node (QrtrNode *node)
-{
- g_autofree gchar *uri = NULL;
-
- uri = qrtr_get_uri_for_node (qrtr_node_get_id (node));
- return qmi_file_new (g_file_new_for_uri (uri));
-}
-#endif
-
-static void
-set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- QmiDevice *self = QMI_DEVICE (object);
-
- switch (prop_id) {
- case PROP_FILE: {
- GFile *file;
-
- file = g_value_get_object (value);
- g_assert (!self->priv->file);
- self->priv->file = file ? qmi_file_new (file) : NULL;
- break;
- }
- case PROP_NO_FILE_CHECK:
- self->priv->no_file_check = g_value_get_boolean (value);
- break;
- case PROP_PROXY_PATH:
- g_free (self->priv->proxy_path);
- self->priv->proxy_path = g_value_dup_string (value);
- break;
-#if QMI_QRTR_SUPPORTED
- case PROP_NODE:
- g_assert (!self->priv->node);
- self->priv->node = g_value_dup_object (value);
- if (self->priv->node) {
- g_assert (!self->priv->file);
- self->priv->file = get_file_for_node (self->priv->node);
- }
- break;
-#endif
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- QmiDevice *self = QMI_DEVICE (object);
-
- switch (prop_id) {
- case PROP_FILE:
- g_assert (QMI_IS_FILE (self->priv->file));
- g_value_set_object (value, qmi_file_get_file (self->priv->file));
- break;
- case PROP_WWAN_IFACE:
- reload_wwan_iface_name (self);
- g_value_set_string (value, self->priv->wwan_iface);
- break;
-#if QMI_QRTR_SUPPORTED
- case PROP_NODE:
- g_value_set_object (value, self->priv->node);
- break;
-#endif
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-qmi_device_init (QmiDevice *self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
- QMI_TYPE_DEVICE,
- QmiDevicePrivate);
-
- self->priv->transactions = g_hash_table_new (g_direct_hash,
- g_direct_equal);
-
- self->priv->registered_clients = g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- self->priv->proxy_path = g_strdup (QMI_PROXY_SOCKET_PATH);
-}
-
-static gboolean
-foreach_warning (gpointer key,
- QmiClient *client,
- QmiDevice *self)
-{
- g_warning ("[%s] QMI client for service '%s' with CID '%u' wasn't released",
- qmi_file_get_path_display (self->priv->file),
- qmi_service_get_string (qmi_client_get_service (client)),
- qmi_client_get_cid (client));
-
- return TRUE;
-}
-
-static void
-dispose (GObject *object)
-{
- QmiDevice *self = QMI_DEVICE (object);
-
- /* unregister our CTL client */
- if (self->priv->client_ctl)
- unregister_client (self, QMI_CLIENT (self->priv->client_ctl));
-
- /* If clients were left unreleased, we'll just warn about it.
- * There is no point in trying to request CID releases, as the device
- * itself is being disposed. */
- g_hash_table_foreach_remove (self->priv->registered_clients,
- (GHRFunc)foreach_warning,
- self);
-
- if (self->priv->sync_indication_id &&
- self->priv->client_ctl) {
- g_signal_handler_disconnect (self->priv->client_ctl,
- self->priv->sync_indication_id);
- self->priv->sync_indication_id = 0;
- }
- g_clear_object (&self->priv->client_ctl);
-
- if (self->priv->endpoint) {
- if (self->priv->endpoint_hangup_id) {
- g_signal_handler_disconnect (self->priv->endpoint, self->priv->endpoint_hangup_id);
- self->priv->endpoint_hangup_id = 0;
- }
- if (self->priv->endpoint_new_data_id) {
- g_signal_handler_disconnect (self->priv->endpoint, self->priv->endpoint_new_data_id);
- self->priv->endpoint_new_data_id = 0;
- }
- g_clear_object (&self->priv->endpoint);
- }
-
- g_clear_object (&self->priv->net_port_manager);
- g_clear_object (&self->priv->file);
-
-#if QMI_QRTR_SUPPORTED
- g_clear_object (&self->priv->node);
-#endif
-
- G_OBJECT_CLASS (qmi_device_parent_class)->dispose (object);
-}
-
-static void
-finalize (GObject *object)
-{
- QmiDevice *self = QMI_DEVICE (object);
-
- /* Transactions keep refs to the device, so it's actually
- * impossible to have any content in the HT */
- if (self->priv->transactions) {
- g_assert (g_hash_table_size (self->priv->transactions) == 0);
- g_hash_table_unref (self->priv->transactions);
- }
-
- g_hash_table_unref (self->priv->registered_clients);
-
- if (self->priv->supported_services)
- g_array_unref (self->priv->supported_services);
-
- g_free (self->priv->proxy_path);
- g_free (self->priv->wwan_iface);
-
- G_OBJECT_CLASS (qmi_device_parent_class)->finalize (object);
-}
-
-static void
-async_initable_iface_init (GAsyncInitableIface *iface)
-{
- iface->init_async = initable_init_async;
- iface->init_finish = initable_init_finish;
-}
-
-static void
-qmi_device_class_init (QmiDeviceClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (QmiDevicePrivate));
-
- object_class->get_property = get_property;
- object_class->set_property = set_property;
- object_class->finalize = finalize;
- object_class->dispose = dispose;
-
- /**
- * QmiDevice:device-file:
- *
- * Since: 1.0
- */
- properties[PROP_FILE] =
- g_param_spec_object (QMI_DEVICE_FILE,
- "Device file",
- "File to the underlying QMI device",
- G_TYPE_FILE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
- g_object_class_install_property (object_class, PROP_FILE, properties[PROP_FILE]);
-
- /**
- * QmiDevice:device-no-file-check:
- *
- * Since: 1.12
- */
- properties[PROP_NO_FILE_CHECK] =
- g_param_spec_boolean (QMI_DEVICE_NO_FILE_CHECK,
- "No file check",
- "Don't check for file existence when creating the Qmi device.",
- FALSE,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
- g_object_class_install_property (object_class, PROP_NO_FILE_CHECK, properties[PROP_NO_FILE_CHECK]);
-
- /**
- * QmiDevice:device-proxy-path:
- *
- * Since: 1.12
- */
- properties[PROP_PROXY_PATH] =
- g_param_spec_string (QMI_DEVICE_PROXY_PATH,
- "Proxy path",
- "Path of the abstract socket where the proxy is available.",
- QMI_PROXY_SOCKET_PATH,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
- g_object_class_install_property (object_class, PROP_PROXY_PATH, properties[PROP_PROXY_PATH]);
-
- /**
- * QmiDevice:device-wwan-iface:
- *
- * Since: 1.14
- */
- properties[PROP_WWAN_IFACE] =
- g_param_spec_string (QMI_DEVICE_WWAN_IFACE,
- "WWAN iface",
- "Name of the WWAN network interface associated with the control port.",
- NULL,
- G_PARAM_READABLE);
- g_object_class_install_property (object_class, PROP_WWAN_IFACE, properties[PROP_WWAN_IFACE]);
-
- /**
- * QmiDevice:device-node:
- *
- * Since: 1.24
- */
-#if QMI_QRTR_SUPPORTED
- properties[PROP_NODE] =
- g_param_spec_object (QMI_DEVICE_NODE,
- "QRTR node",
- "Remote node on the QRTR bus",
- QRTR_TYPE_NODE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
- g_object_class_install_property (object_class, PROP_NODE, properties[PROP_NODE]);
-#endif
-
- /**
- * QmiDevice::indication:
- * @object: A #QmiDevice.
- * @output: A #QmiMessage.
- *
- * The ::indication signal gets emitted when a QMI indication is received.
- *
- * Since: 1.8
- */
- signals[SIGNAL_INDICATION] =
- g_signal_new (QMI_DEVICE_SIGNAL_INDICATION,
- G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- G_TYPE_BYTE_ARRAY);
-
- /**
- * QmiDevice::device-removed:
- * @object: A #QmiDevice.
- * @output: none
- *
- * The ::device-removed signal is emitted when an unexpected port hang-up is received.
- *
- * Since: 1.20
- */
- signals[SIGNAL_REMOVED] =
- g_signal_new (QMI_DEVICE_SIGNAL_REMOVED,
- G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 0);
-}
diff --git a/src/libqmi-glib/.#qmi-device.c b/src/libqmi-glib/.#qmi-device.c
deleted file mode 120000
index f601aaa6..00000000
--- a/src/libqmi-glib/.#qmi-device.c
+++ /dev/null
@@ -1 +0,0 @@
-aleksander@ares.4689:1656059922 \ No newline at end of file