port-mbim: automatically try to open a QMI over MBIM device

Most Qualcomm-based MBIM devices also support QMI over MBIM. We will
try to check in runtime whether the MBIM device supports QMI over
MBIM, and if so, setup a QmiDevice within the MMPortMbim.
This commit is contained in:
Aleksander Morgado
2018-06-19 11:55:10 +02:00
committed by Dan Williams
parent f6a2d01c7e
commit c0cc694c67
4 changed files with 151 additions and 18 deletions

View File

@@ -1953,6 +1953,9 @@ initialization_started (MMBroadbandModem *self,
/* Now open our MBIM port */
mm_port_mbim_open (ctx->mbim,
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
TRUE, /* With QMI over MBIM support if available */
#endif
NULL,
(GAsyncReadyCallback)mbim_port_open_ready,
task);

View File

@@ -10,12 +10,18 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
* Copyright (C) 2013-2018 Aleksander Morgado <aleksander@gnu.org>
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#if defined WITH_QMI
# include <libqmi-glib.h>
#endif
#include <ModemManager.h>
#include <mm-errors-types.h>
@@ -25,26 +31,98 @@
G_DEFINE_TYPE (MMPortMbim, mm_port_mbim, MM_TYPE_PORT)
struct _MMPortMbimPrivate {
gboolean in_progress;
gboolean in_progress;
MbimDevice *mbim_device;
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
QmiDevice *qmi_device;
#endif
};
/*****************************************************************************/
gboolean
mm_port_mbim_open_finish (MMPortMbim *self,
GAsyncResult *res,
GError **error)
mm_port_mbim_open_finish (MMPortMbim *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
static void
mbim_device_open_ready (MbimDevice *mbim_device,
GAsyncResult *res,
GTask *task)
qmi_device_open_ready (QmiDevice *dev,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
GError *error = NULL;
MMPortMbim *self;
self = g_task_get_source_object (task);
if (!qmi_device_open_finish (dev, res, &error)) {
mm_dbg ("[%s] error: couldn't open QmiDevice: %s",
mm_port_get_device (MM_PORT (self)),
error->message);
g_error_free (error);
g_clear_object (&self->priv->qmi_device);
/* Ignore error and complete */
mm_info ("[%s] MBIM device is not QMI capable",
mm_port_get_device (MM_PORT (self)));
} else {
mm_info ("[%s] MBIM device is QMI capable",
mm_port_get_device (MM_PORT (self)));
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
qmi_device_new_ready (GObject *unused,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
MMPortMbim *self;
self = g_task_get_source_object (task);
self->priv->qmi_device = qmi_device_new_finish (res, &error);
if (!self->priv->qmi_device) {
mm_dbg ("[%s] error: couldn't create QmiDevice: %s",
mm_port_get_device (MM_PORT (self)),
error->message);
g_error_free (error);
/* Ignore error and complete */
mm_info ("[%s] MBIM device is not QMI capable",
mm_port_get_device (MM_PORT (self)));
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
/* Try to open using QMI over MBIM */
mm_dbg ("[%s] trying to open QMI over MBIM device...",
mm_port_get_device (MM_PORT (self)));
qmi_device_open (self->priv->qmi_device,
(QMI_DEVICE_OPEN_FLAGS_PROXY |
QMI_DEVICE_OPEN_FLAGS_MBIM |
QMI_DEVICE_OPEN_FLAGS_VERSION_INFO),
15,
g_task_get_cancellable (task),
(GAsyncReadyCallback)qmi_device_open_ready,
task);
}
#endif
static void
mbim_device_open_ready (MbimDevice *mbim_device,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
MMPortMbim *self;
self = g_task_get_source_object (task);
@@ -54,18 +132,40 @@ mbim_device_open_ready (MbimDevice *mbim_device,
if (!mbim_device_open_full_finish (mbim_device, res, &error)) {
g_clear_object (&self->priv->mbim_device);
g_task_return_error (task, error);
} else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
mm_dbg ("[%s] MBIM device is now open",
mm_port_get_device (MM_PORT (self)));
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
{
GFile *file;
if ((file = G_FILE (g_task_get_task_data (task)))) {
mm_dbg ("[%s] checking if QMI over MBIM is supported",
mm_port_get_device (MM_PORT (self)));
qmi_device_new (file,
g_task_get_cancellable (task),
(GAsyncReadyCallback) qmi_device_new_ready,
task);
return;
}
}
#endif
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
mbim_device_new_ready (GObject *unused,
mbim_device_new_ready (GObject *unused,
GAsyncResult *res,
GTask *task)
GTask *task)
{
GError *error = NULL;
GError *error = NULL;
MMPortMbim *self;
self = g_task_get_source_object (task);
@@ -86,10 +186,13 @@ mbim_device_new_ready (GObject *unused,
}
void
mm_port_mbim_open (MMPortMbim *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
mm_port_mbim_open (MMPortMbim *self,
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
gboolean try_qmi_over_mbim,
#endif
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GFile *file;
gchar *fullpath;
@@ -117,6 +220,10 @@ mm_port_mbim_open (MMPortMbim *self,
fullpath = g_strdup_printf ("/dev/%s", mm_port_get_device (MM_PORT (self)));
file = g_file_new_for_path (fullpath);
/* If we want to try QMI over MBIM, store the GFile as task data */
if (try_qmi_over_mbim)
g_task_set_task_data (task, g_object_ref (file), g_object_unref);
self->priv->in_progress = TRUE;
mbim_device_new (file,
cancellable,
@@ -194,6 +301,19 @@ mm_port_mbim_close (MMPortMbim *self,
}
self->priv->in_progress = TRUE;
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
if (self->priv->qmi_device) {
GError *error = NULL;
if (!qmi_device_close (self->priv->qmi_device, &error)) {
mm_warn ("Couldn't properly close QMI device: %s", error->message);
g_error_free (error);
}
g_clear_object (&self->priv->qmi_device);
}
#endif
mbim_device_close (self->priv->mbim_device,
5,
NULL,
@@ -235,6 +355,10 @@ dispose (GObject *object)
{
MMPortMbim *self = MM_PORT_MBIM (object);
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
g_clear_object (&self->priv->qmi_device);
#endif
/* Clear device object */
g_clear_object (&self->priv->mbim_device);

View File

@@ -49,6 +49,9 @@ GType mm_port_mbim_get_type (void);
MMPortMbim *mm_port_mbim_new (const gchar *name);
void mm_port_mbim_open (MMPortMbim *self,
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
gboolean try_qmi_over_mbim,
#endif
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

View File

@@ -557,6 +557,9 @@ wdm_probe_mbim (MMPortProbe *self)
/* Create a port and try to open it */
ctx->mbim_port = mm_port_mbim_new (mm_kernel_device_get_name (self->priv->port));
mm_port_mbim_open (ctx->mbim_port,
#if WITH_QMI
FALSE, /* Don't check QMI over MBIM support at this stage */
#endif
NULL,
(GAsyncReadyCallback) mbim_port_open_ready,
self);