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:

committed by
Dan Williams

parent
f6a2d01c7e
commit
c0cc694c67
@@ -1953,6 +1953,9 @@ initialization_started (MMBroadbandModem *self,
|
|||||||
|
|
||||||
/* Now open our MBIM port */
|
/* Now open our MBIM port */
|
||||||
mm_port_mbim_open (ctx->mbim,
|
mm_port_mbim_open (ctx->mbim,
|
||||||
|
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||||
|
TRUE, /* With QMI over MBIM support if available */
|
||||||
|
#endif
|
||||||
NULL,
|
NULL,
|
||||||
(GAsyncReadyCallback)mbim_port_open_ready,
|
(GAsyncReadyCallback)mbim_port_open_ready,
|
||||||
task);
|
task);
|
||||||
|
@@ -10,12 +10,18 @@
|
|||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details:
|
* 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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined WITH_QMI
|
||||||
|
# include <libqmi-glib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <ModemManager.h>
|
#include <ModemManager.h>
|
||||||
#include <mm-errors-types.h>
|
#include <mm-errors-types.h>
|
||||||
|
|
||||||
@@ -25,26 +31,98 @@
|
|||||||
G_DEFINE_TYPE (MMPortMbim, mm_port_mbim, MM_TYPE_PORT)
|
G_DEFINE_TYPE (MMPortMbim, mm_port_mbim, MM_TYPE_PORT)
|
||||||
|
|
||||||
struct _MMPortMbimPrivate {
|
struct _MMPortMbimPrivate {
|
||||||
gboolean in_progress;
|
gboolean in_progress;
|
||||||
MbimDevice *mbim_device;
|
MbimDevice *mbim_device;
|
||||||
|
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||||
|
QmiDevice *qmi_device;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
mm_port_mbim_open_finish (MMPortMbim *self,
|
mm_port_mbim_open_finish (MMPortMbim *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
return g_task_propagate_boolean (G_TASK (res), error);
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mbim_device_open_ready (MbimDevice *mbim_device,
|
qmi_device_open_ready (QmiDevice *dev,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GTask *task)
|
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;
|
MMPortMbim *self;
|
||||||
|
|
||||||
self = g_task_get_source_object (task);
|
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)) {
|
if (!mbim_device_open_full_finish (mbim_device, res, &error)) {
|
||||||
g_clear_object (&self->priv->mbim_device);
|
g_clear_object (&self->priv->mbim_device);
|
||||||
g_task_return_error (task, error);
|
g_task_return_error (task, error);
|
||||||
} else
|
g_object_unref (task);
|
||||||
g_task_return_boolean (task, TRUE);
|
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);
|
g_object_unref (task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mbim_device_new_ready (GObject *unused,
|
mbim_device_new_ready (GObject *unused,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GTask *task)
|
GTask *task)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
MMPortMbim *self;
|
MMPortMbim *self;
|
||||||
|
|
||||||
self = g_task_get_source_object (task);
|
self = g_task_get_source_object (task);
|
||||||
@@ -86,10 +186,13 @@ mbim_device_new_ready (GObject *unused,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mm_port_mbim_open (MMPortMbim *self,
|
mm_port_mbim_open (MMPortMbim *self,
|
||||||
GCancellable *cancellable,
|
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||||
GAsyncReadyCallback callback,
|
gboolean try_qmi_over_mbim,
|
||||||
gpointer user_data)
|
#endif
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GFile *file;
|
GFile *file;
|
||||||
gchar *fullpath;
|
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)));
|
fullpath = g_strdup_printf ("/dev/%s", mm_port_get_device (MM_PORT (self)));
|
||||||
file = g_file_new_for_path (fullpath);
|
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;
|
self->priv->in_progress = TRUE;
|
||||||
mbim_device_new (file,
|
mbim_device_new (file,
|
||||||
cancellable,
|
cancellable,
|
||||||
@@ -194,6 +301,19 @@ mm_port_mbim_close (MMPortMbim *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
self->priv->in_progress = TRUE;
|
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,
|
mbim_device_close (self->priv->mbim_device,
|
||||||
5,
|
5,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -235,6 +355,10 @@ dispose (GObject *object)
|
|||||||
{
|
{
|
||||||
MMPortMbim *self = MM_PORT_MBIM (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 */
|
/* Clear device object */
|
||||||
g_clear_object (&self->priv->mbim_device);
|
g_clear_object (&self->priv->mbim_device);
|
||||||
|
|
||||||
|
@@ -49,6 +49,9 @@ GType mm_port_mbim_get_type (void);
|
|||||||
MMPortMbim *mm_port_mbim_new (const gchar *name);
|
MMPortMbim *mm_port_mbim_new (const gchar *name);
|
||||||
|
|
||||||
void mm_port_mbim_open (MMPortMbim *self,
|
void mm_port_mbim_open (MMPortMbim *self,
|
||||||
|
#if WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||||
|
gboolean try_qmi_over_mbim,
|
||||||
|
#endif
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
@@ -557,6 +557,9 @@ wdm_probe_mbim (MMPortProbe *self)
|
|||||||
/* Create a port and try to open it */
|
/* Create a port and try to open it */
|
||||||
ctx->mbim_port = mm_port_mbim_new (mm_kernel_device_get_name (self->priv->port));
|
ctx->mbim_port = mm_port_mbim_new (mm_kernel_device_get_name (self->priv->port));
|
||||||
mm_port_mbim_open (ctx->mbim_port,
|
mm_port_mbim_open (ctx->mbim_port,
|
||||||
|
#if WITH_QMI
|
||||||
|
FALSE, /* Don't check QMI over MBIM support at this stage */
|
||||||
|
#endif
|
||||||
NULL,
|
NULL,
|
||||||
(GAsyncReadyCallback) mbim_port_open_ready,
|
(GAsyncReadyCallback) mbim_port_open_ready,
|
||||||
self);
|
self);
|
||||||
|
Reference in New Issue
Block a user