port-probe: include MBIM port probing logic

This commit is contained in:
Aleksander Morgado
2013-04-17 15:19:37 +02:00
parent dd5680debe
commit 3d2c0cc83c
6 changed files with 500 additions and 25 deletions
+14 -1
View File
@@ -83,7 +83,7 @@ libserial_la_SOURCES = \
mm-gps-serial-port.c \
mm-gps-serial-port.h
# Additional QMI support in libmodem-helpers
# Additional QMI support in libserial
if WITH_QMI
libserial_la_SOURCES += \
mm-qmi-port.c \
@@ -91,6 +91,14 @@ libserial_la_SOURCES += \
libserial_la_CPPFLAGS += $(QMI_CFLAGS)
endif
# Additional MBIM support in libserial
if WITH_MBIM
libserial_la_SOURCES += \
mm-mbim-port.c \
mm-mbim-port.h
libserial_la_CPPFLAGS += $(MBIM_CFLAGS)
endif
# Daemon specific enum types
DAEMON_ENUMS = \
$(srcdir)/mm-bearer.h \
@@ -239,6 +247,11 @@ ModemManager_CPPFLAGS += $(QMI_CFLAGS)
ModemManager_LDADD += $(QMI_LIBS)
endif
# Additional MBIM support in ModemManager
if WITH_MBIM
ModemManager_CPPFLAGS += $(MBIM_CFLAGS)
ModemManager_LDADD += $(MBIM_LIBS)
endif
EXTRA_DIST = \
$(udevrules_DATA) \
+226
View File
@@ -0,0 +1,226 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details:
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
*/
#include <stdio.h>
#include <stdlib.h>
#include <ModemManager.h>
#include <mm-errors-types.h>
#include "mm-mbim-port.h"
#include "mm-log.h"
G_DEFINE_TYPE (MMMbimPort, mm_mbim_port, MM_TYPE_PORT)
struct _MMMbimPortPrivate {
gboolean opening;
MbimDevice *mbim_device;
};
/*****************************************************************************/
typedef struct {
MMMbimPort *self;
GSimpleAsyncResult *result;
GCancellable *cancellable;
} PortOpenContext;
static void
port_open_context_complete_and_free (PortOpenContext *ctx)
{
g_simple_async_result_complete_in_idle (ctx->result);
if (ctx->cancellable)
g_object_unref (ctx->cancellable);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
g_slice_free (PortOpenContext, ctx);
}
gboolean
mm_mbim_port_open_finish (MMMbimPort *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
mbim_device_open_ready (MbimDevice *mbim_device,
GAsyncResult *res,
PortOpenContext *ctx)
{
GError *error = NULL;
/* Reset the opening flag */
ctx->self->priv->opening = FALSE;
if (!mbim_device_open_finish (mbim_device, res, &error)) {
g_clear_object (&ctx->self->priv->mbim_device);
g_simple_async_result_take_error (ctx->result, error);
} else
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
port_open_context_complete_and_free (ctx);
}
static void
mbim_device_new_ready (GObject *unused,
GAsyncResult *res,
PortOpenContext *ctx)
{
GError *error = NULL;
ctx->self->priv->mbim_device = mbim_device_new_finish (res, &error);
if (!ctx->self->priv->mbim_device) {
g_simple_async_result_take_error (ctx->result, error);
port_open_context_complete_and_free (ctx);
return;
}
/* Now open the MBIM device */
mbim_device_open (ctx->self->priv->mbim_device,
10,
ctx->cancellable,
(GAsyncReadyCallback)mbim_device_open_ready,
ctx);
}
void
mm_mbim_port_open (MMMbimPort *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GFile *file;
gchar *fullpath;
PortOpenContext *ctx;
g_return_if_fail (MM_IS_MBIM_PORT (self));
ctx = g_slice_new0 (PortOpenContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
mm_mbim_port_open);
ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (self->priv->opening) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_IN_PROGRESS,
"MBIM device already being opened");
port_open_context_complete_and_free (ctx);
return;
}
if (self->priv->mbim_device) {
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
port_open_context_complete_and_free (ctx);
return;
}
fullpath = g_strdup_printf ("/dev/%s", mm_port_get_device (MM_PORT (self)));
file = g_file_new_for_path (fullpath);
self->priv->opening = TRUE;
mbim_device_new (file,
ctx->cancellable,
(GAsyncReadyCallback)mbim_device_new_ready,
ctx);
g_free (fullpath);
g_object_unref (file);
}
gboolean
mm_mbim_port_is_open (MMMbimPort *self)
{
g_return_val_if_fail (MM_IS_MBIM_PORT (self), FALSE);
return !!self->priv->mbim_device;
}
static void
mbim_device_close_ready (MbimDevice *device,
GAsyncResult *res)
{
GError *error = NULL;
if (!mbim_device_close_finish (device, res, &error)) {
mm_warn ("Couldn't properly close MBIM device: %s",
error->message);
g_error_free (error);
}
}
void
mm_mbim_port_close (MMMbimPort *self)
{
g_return_if_fail (MM_IS_MBIM_PORT (self));
if (!self->priv->mbim_device)
return;
/* Close and release the device. This method is async,
* but we don't really care about the result. */
mbim_device_close (self->priv->mbim_device,
5,
NULL,
(GAsyncReadyCallback)mbim_device_close_ready,
NULL);
g_clear_object (&self->priv->mbim_device);
}
/*****************************************************************************/
MMMbimPort *
mm_mbim_port_new (const gchar *name)
{
return MM_MBIM_PORT (g_object_new (MM_TYPE_MBIM_PORT,
MM_PORT_DEVICE, name,
MM_PORT_SUBSYS, MM_PORT_SUBSYS_USB,
MM_PORT_TYPE, MM_PORT_TYPE_MBIM,
NULL));
}
static void
mm_mbim_port_init (MMMbimPort *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_MBIM_PORT, MMMbimPortPrivate);
}
static void
dispose (GObject *object)
{
MMMbimPort *self = MM_MBIM_PORT (object);
/* Clear device object */
g_clear_object (&self->priv->mbim_device);
G_OBJECT_CLASS (mm_mbim_port_parent_class)->dispose (object);
}
static void
mm_mbim_port_class_init (MMMbimPortClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMMbimPortPrivate));
/* Virtual methods */
object_class->dispose = dispose;
}
+61
View File
@@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details:
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
*/
#ifndef MM_MBIM_PORT_H
#define MM_MBIM_PORT_H
#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <libmbim-glib.h>
#include "mm-port.h"
#define MM_TYPE_MBIM_PORT (mm_mbim_port_get_type ())
#define MM_MBIM_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MBIM_PORT, MMMbimPort))
#define MM_MBIM_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MBIM_PORT, MMMbimPortClass))
#define MM_IS_MBIM_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MBIM_PORT))
#define MM_IS_MBIM_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MBIM_PORT))
#define MM_MBIM_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MBIM_PORT, MMMbimPortClass))
typedef struct _MMMbimPort MMMbimPort;
typedef struct _MMMbimPortClass MMMbimPortClass;
typedef struct _MMMbimPortPrivate MMMbimPortPrivate;
struct _MMMbimPort {
MMPort parent;
MMMbimPortPrivate *priv;
};
struct _MMMbimPortClass {
MMPortClass parent;
};
GType mm_mbim_port_get_type (void);
MMMbimPort *mm_mbim_port_new (const gchar *name);
void mm_mbim_port_open (MMMbimPort *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_mbim_port_open_finish (MMMbimPort *self,
GAsyncResult *res,
GError **error);
gboolean mm_mbim_port_is_open (MMMbimPort *self);
void mm_mbim_port_close (MMMbimPort *self);
#endif /* MM_MBIM_PORT_H */
+188 -19
View File
@@ -40,6 +40,10 @@
#include "mm-qmi-port.h"
#endif
#if defined WITH_MBIM
#include "mm-mbim-port.h"
#endif
/*
* Steps and flow of the Probing process:
* ----> AT Serial Open
@@ -52,6 +56,8 @@
* |----> QCDM?
* ----> QMI Device Open
* |----> QMI Version Info check
* ----> MBIM Device Open
* |----> MBIM capabilities check
*/
G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT)
@@ -106,6 +112,11 @@ typedef struct {
MMQmiPort *qmi_port;
#endif
#if defined WITH_MBIM
/* ---- MBIM probing specific context ---- */
MMMbimPort *mbim_port;
#endif
} PortProbeRunTask;
struct _MMPortProbePrivate {
@@ -121,6 +132,7 @@ struct _MMPortProbePrivate {
gchar *product;
gboolean is_icera;
gboolean is_qmi;
gboolean is_mbim;
/* Current probing task. Only one can be available at a time */
PortProbeRunTask *task;
@@ -138,10 +150,11 @@ mm_port_probe_set_result_at (MMPortProbe *self,
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
/* Also set as not a QCDM/QMI port */
/* Also set as not a QCDM/QMI/MBIM port */
self->priv->is_qcdm = FALSE;
self->priv->is_qmi = FALSE;
self->priv->flags |= (MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI);
self->priv->is_mbim = FALSE;
self->priv->flags |= (MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI | MM_PORT_PROBE_MBIM);
} else {
mm_dbg ("(%s/%s) port is not AT-capable",
g_udev_device_get_subsystem (self->priv->port),
@@ -225,9 +238,10 @@ mm_port_probe_set_result_qcdm (MMPortProbe *self,
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
/* Also set as not an AT/QMI port */
/* Also set as not an AT/QMI/MBIM port */
self->priv->is_at = FALSE;
self->priv->is_qmi = FALSE;
self->priv->is_mbim = FALSE;
self->priv->vendor = NULL;
self->priv->product = NULL;
self->priv->is_icera = FALSE;
@@ -235,7 +249,8 @@ mm_port_probe_set_result_qcdm (MMPortProbe *self,
MM_PORT_PROBE_AT_VENDOR |
MM_PORT_PROBE_AT_PRODUCT |
MM_PORT_PROBE_AT_ICERA |
MM_PORT_PROBE_QMI);
MM_PORT_PROBE_QMI |
MM_PORT_PROBE_MBIM);
} else
mm_dbg ("(%s/%s) port is not QCDM-capable",
g_udev_device_get_subsystem (self->priv->port),
@@ -254,22 +269,54 @@ mm_port_probe_set_result_qmi (MMPortProbe *self,
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
/* Also set as not an AT/QCDM port */
/* Also set as not an AT/QCDM/MBIM port */
self->priv->is_at = FALSE;
self->priv->is_qcdm = FALSE;
self->priv->is_mbim = FALSE;
self->priv->vendor = NULL;
self->priv->product = NULL;
self->priv->flags |= (MM_PORT_PROBE_AT |
MM_PORT_PROBE_AT_VENDOR |
MM_PORT_PROBE_AT_PRODUCT |
MM_PORT_PROBE_AT_ICERA |
MM_PORT_PROBE_QCDM);
MM_PORT_PROBE_QCDM |
MM_PORT_PROBE_MBIM);
} else
mm_dbg ("(%s/%s) port is not QMI-capable",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
}
void
mm_port_probe_set_result_mbim (MMPortProbe *self,
gboolean mbim)
{
self->priv->is_mbim = mbim;
self->priv->flags |= MM_PORT_PROBE_MBIM;
if (self->priv->is_mbim) {
mm_dbg ("(%s/%s) port is MBIM-capable",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
/* Also set as not an AT/QCDM/QMI port */
self->priv->is_at = FALSE;
self->priv->is_qcdm = FALSE;
self->priv->is_qmi = FALSE;
self->priv->vendor = NULL;
self->priv->product = NULL;
self->priv->flags |= (MM_PORT_PROBE_AT |
MM_PORT_PROBE_AT_VENDOR |
MM_PORT_PROBE_AT_PRODUCT |
MM_PORT_PROBE_AT_ICERA |
MM_PORT_PROBE_QCDM |
MM_PORT_PROBE_QMI);
} else
mm_dbg ("(%s/%s) port is not MBIM-capable",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
}
static gboolean serial_probe_at (MMPortProbe *self);
static gboolean serial_probe_qcdm (MMPortProbe *self);
static void serial_probe_schedule (MMPortProbe *self);
@@ -296,6 +343,14 @@ port_probe_run_task_free (PortProbeRunTask *task)
}
#endif
#if defined WITH_MBIM
if (task->mbim_port) {
if (mm_mbim_port_is_open (task->mbim_port))
mm_mbim_port_close (task->mbim_port);
g_object_unref (task->mbim_port);
}
#endif
if (task->cancellable)
g_object_unref (task->cancellable);
if (task->at_probing_cancellable)
@@ -352,7 +407,9 @@ port_probe_run_is_cancelled (MMPortProbe *self)
}
/***************************************************************/
/* QMI */
/* QMI & MBIM */
static gboolean wdm_probe (MMPortProbe *self);
#if defined WITH_QMI
@@ -379,21 +436,17 @@ qmi_port_open_ready (MMQmiPort *qmi_port,
mm_qmi_port_close (qmi_port);
/* All done! Finish asynchronously */
port_probe_run_task_complete (task, TRUE, NULL);
/* Keep on */
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
}
#endif /* WITH_QMI */
static gboolean
static void
wdm_probe_qmi (MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
/* If already cancelled, do nothing else */
if (port_probe_run_is_cancelled (self))
return FALSE;
#if defined WITH_QMI
mm_dbg ("(%s/%s) probing QMI...",
g_udev_device_get_subsystem (self->priv->port),
@@ -409,8 +462,86 @@ wdm_probe_qmi (MMPortProbe *self)
#else
/* If not compiled with QMI support, just assume we won't have any QMI port */
mm_port_probe_set_result_qmi (self, FALSE);
port_probe_run_task_complete (task, TRUE, NULL);
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
#endif /* WITH_QMI */
}
#if defined WITH_MBIM
static void
mbim_port_open_ready (MMMbimPort *mbim_port,
GAsyncResult *res,
MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
GError *error = NULL;
gboolean is_mbim;
is_mbim = mm_mbim_port_open_finish (mbim_port, res, &error);
if (!is_mbim) {
mm_dbg ("(%s/%s) error checking MBIM support: '%s'",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port),
error ? error->message : "unknown error");
g_clear_error (&error);
}
/* Set probing result */
mm_port_probe_set_result_mbim (self, is_mbim);
mm_mbim_port_close (mbim_port);
/* Keep on */
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
}
#endif /* WITH_MBIM */
static void
wdm_probe_mbim (MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
#if defined WITH_MBIM
mm_dbg ("(%s/%s) probing MBIM...",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
/* Create a port and try to open it */
task->mbim_port = mm_mbim_port_new (g_udev_device_get_name (self->priv->port));
mm_mbim_port_open (task->mbim_port,
NULL,
(GAsyncReadyCallback)mbim_port_open_ready,
self);
#else
/* If not compiled with MBIM support, just assume we won't have any MBIM port */
mm_port_probe_set_result_mbim (self, FALSE);
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
#endif /* WITH_MBIM */
}
static gboolean
wdm_probe (MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
task->source_id = 0;
/* If already cancelled, do nothing else */
if (port_probe_run_is_cancelled (self))
return FALSE;
if ((task->flags & MM_PORT_PROBE_QMI) &&
!(self->priv->flags & MM_PORT_PROBE_QMI))
/* QMI probing needed */
wdm_probe_qmi (self);
else if ((task->flags & MM_PORT_PROBE_MBIM) &&
!(self->priv->flags & MM_PORT_PROBE_MBIM))
/* MBIM probing needed */
wdm_probe_mbim (self);
else
/* All done now */
port_probe_run_task_complete (task, TRUE, NULL);
return FALSE;
}
@@ -1151,7 +1282,7 @@ mm_port_probe_run (MMPortProbe *self,
/* Check if we already have the requested probing results.
* We will fix here the 'task->flags' so that we only request probing
* for the missing things. */
for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_QMI; i = (i << 1)) {
for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_MBIM; i = (i << 1)) {
if ((flags & i) && !(self->priv->flags & i)) {
task->flags += i;
}
@@ -1193,9 +1324,9 @@ mm_port_probe_run (MMPortProbe *self,
return;
}
/* If QMI probing needed, start by opening as a QMI port */
if (task->flags & MM_PORT_PROBE_QMI) {
task->source_id = g_idle_add ((GSourceFunc)wdm_probe_qmi, self);
/* If QMI/MBIM probing needed, go on */
if (task->flags & MM_PORT_PROBE_QMI || task->flags & MM_PORT_PROBE_MBIM) {
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
return;
}
@@ -1289,6 +1420,37 @@ mm_port_probe_list_has_qmi_port (GList *list)
return FALSE;
}
gboolean
mm_port_probe_is_mbim (MMPortProbe *self)
{
const gchar *subsys;
const gchar *name;
g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE);
subsys = g_udev_device_get_subsystem (self->priv->port);
name = g_udev_device_get_name (self->priv->port);
if (!g_str_has_prefix (subsys, "usb") ||
!name ||
!g_str_has_prefix (name, "cdc-wdm"))
return FALSE;
return self->priv->is_mbim;
}
gboolean
mm_port_probe_list_has_mbim_port (GList *list)
{
GList *l;
for (l = list; l; l = g_list_next (l)) {
if (mm_port_probe_is_mbim (MM_PORT_PROBE (l->data)))
return TRUE;
}
return FALSE;
}
MMPortType
mm_port_probe_get_port_type (MMPortProbe *self)
{
@@ -1310,6 +1472,13 @@ mm_port_probe_get_port_type (MMPortProbe *self)
return MM_PORT_TYPE_QMI;
#endif
#if defined WITH_MBIM
if (g_str_has_prefix (subsys, "usb") &&
g_str_has_prefix (name, "cdc-wdm") &&
self->priv->is_mbim)
return MM_PORT_TYPE_MBIM;
#endif
if (self->priv->flags & MM_PORT_PROBE_QCDM &&
self->priv->is_qcdm)
return MM_PORT_TYPE_QCDM;
+9 -4
View File
@@ -43,7 +43,8 @@ typedef enum { /*< underscore_name=mm_port_probe_flag >*/
MM_PORT_PROBE_AT_PRODUCT = 1 << 2,
MM_PORT_PROBE_AT_ICERA = 1 << 3,
MM_PORT_PROBE_QCDM = 1 << 4,
MM_PORT_PROBE_QMI = 1 << 5
MM_PORT_PROBE_QMI = 1 << 5,
MM_PORT_PROBE_MBIM = 1 << 6
} MMPortProbeFlag;
typedef struct _MMPortProbe MMPortProbe;
@@ -100,6 +101,8 @@ void mm_port_probe_set_result_qcdm (MMPortProbe *self,
gboolean qcdm);
void mm_port_probe_set_result_qmi (MMPortProbe *self,
gboolean qmi);
void mm_port_probe_set_result_mbim (MMPortProbe *self,
gboolean mbim);
/* Run probing */
void mm_port_probe_run (MMPortProbe *self,
@@ -123,13 +126,15 @@ MMPortType mm_port_probe_get_port_type (MMPortProbe *self);
gboolean mm_port_probe_is_at (MMPortProbe *self);
gboolean mm_port_probe_is_qcdm (MMPortProbe *self);
gboolean mm_port_probe_is_qmi (MMPortProbe *self);
gboolean mm_port_probe_is_mbim (MMPortProbe *self);
const gchar *mm_port_probe_get_vendor (MMPortProbe *self);
const gchar *mm_port_probe_get_product (MMPortProbe *self);
gboolean mm_port_probe_is_icera (MMPortProbe *self);
/* Additional helpers */
gboolean mm_port_probe_list_has_at_port (GList *list);
gboolean mm_port_probe_list_has_qmi_port (GList *list);
gboolean mm_port_probe_list_is_icera (GList *list);
gboolean mm_port_probe_list_has_at_port (GList *list);
gboolean mm_port_probe_list_has_qmi_port (GList *list);
gboolean mm_port_probe_list_has_mbim_port (GList *list);
gboolean mm_port_probe_list_is_icera (GList *list);
#endif /* MM_PORT_PROBE_H */
+2 -1
View File
@@ -37,7 +37,8 @@ typedef enum { /*< underscore_name=mm_port_type >*/
MM_PORT_TYPE_QCDM,
MM_PORT_TYPE_GPS,
MM_PORT_TYPE_QMI,
MM_PORT_TYPE_LAST = MM_PORT_TYPE_QMI /*< skip >*/
MM_PORT_TYPE_MBIM,
MM_PORT_TYPE_LAST = MM_PORT_TYPE_MBIM /*< skip >*/
} MMPortType;
#define MM_TYPE_PORT (mm_port_get_type ())