port-probe: launch QMI probing on cdc-wdm ports
Some devices may export cdc-wdm ports talking AT. We need to explicitly check for QMI protocol support on the cdc-wdm ports before assuming they are QMI.
This commit is contained in:
@@ -589,10 +589,8 @@ mm_plugin_supports_port (MMPlugin *self,
|
|||||||
g_udev_device_get_subsystem (port),
|
g_udev_device_get_subsystem (port),
|
||||||
g_udev_device_get_name (port));
|
g_udev_device_get_name (port));
|
||||||
|
|
||||||
/* Before launching any probing, check if the port is a net OR a wdm device
|
/* Before launching any probing, check if the port is a net device. */
|
||||||
* (which cannot be probed). */
|
if (g_str_equal (g_udev_device_get_subsystem (port), "net")) {
|
||||||
if (g_str_equal (g_udev_device_get_subsystem (port), "net") ||
|
|
||||||
g_str_equal (g_udev_device_get_subsystem (port), "cdc-wdm")) {
|
|
||||||
g_simple_async_result_set_op_res_gpointer (
|
g_simple_async_result_set_op_res_gpointer (
|
||||||
async_result,
|
async_result,
|
||||||
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED),
|
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED),
|
||||||
@@ -602,6 +600,8 @@ mm_plugin_supports_port (MMPlugin *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Build flags depending on what probing needed */
|
/* Build flags depending on what probing needed */
|
||||||
|
if (!g_str_has_prefix (g_udev_device_get_name (port), "cdc-wdm")) {
|
||||||
|
/* Serial ports... */
|
||||||
probe_run_flags = MM_PORT_PROBE_NONE;
|
probe_run_flags = MM_PORT_PROBE_NONE;
|
||||||
if (self->priv->at)
|
if (self->priv->at)
|
||||||
probe_run_flags |= MM_PORT_PROBE_AT;
|
probe_run_flags |= MM_PORT_PROBE_AT;
|
||||||
@@ -615,6 +615,10 @@ mm_plugin_supports_port (MMPlugin *self,
|
|||||||
probe_run_flags |= MM_PORT_PROBE_QCDM;
|
probe_run_flags |= MM_PORT_PROBE_QCDM;
|
||||||
if (self->priv->icera_probe || self->priv->allowed_icera || self->priv->forbidden_icera)
|
if (self->priv->icera_probe || self->priv->allowed_icera || self->priv->forbidden_icera)
|
||||||
probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_ICERA);
|
probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_ICERA);
|
||||||
|
} else {
|
||||||
|
/* cdc-wdm ports... */
|
||||||
|
probe_run_flags = MM_PORT_PROBE_QMI;
|
||||||
|
}
|
||||||
|
|
||||||
g_assert (probe_run_flags != MM_PORT_PROBE_NONE);
|
g_assert (probe_run_flags != MM_PORT_PROBE_NONE);
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "mm-port-probe.h"
|
#include "mm-port-probe.h"
|
||||||
#include "mm-log.h"
|
#include "mm-log.h"
|
||||||
|
#include "mm-qmi-port.h"
|
||||||
#include "mm-at-serial-port.h"
|
#include "mm-at-serial-port.h"
|
||||||
#include "mm-serial-port.h"
|
#include "mm-serial-port.h"
|
||||||
#include "mm-serial-parsers.h"
|
#include "mm-serial-parsers.h"
|
||||||
@@ -44,6 +45,8 @@
|
|||||||
* |----> Is Icera?
|
* |----> Is Icera?
|
||||||
* ----> QCDM Serial Open
|
* ----> QCDM Serial Open
|
||||||
* |----> QCDM?
|
* |----> QCDM?
|
||||||
|
* ----> QMI Device Open
|
||||||
|
* |----> QMI Version Info check
|
||||||
*/
|
*/
|
||||||
|
|
||||||
G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT)
|
||||||
@@ -59,15 +62,21 @@ static GParamSpec *properties[PROP_LAST];
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* ---- Generic task context ---- */
|
/* ---- Generic task context ---- */
|
||||||
|
|
||||||
GSimpleAsyncResult *result;
|
GSimpleAsyncResult *result;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
GCancellable *at_probing_cancellable;
|
|
||||||
guint32 flags;
|
guint32 flags;
|
||||||
guint source_id;
|
guint source_id;
|
||||||
|
|
||||||
|
/* ---- Serial probing specific context ---- */
|
||||||
|
|
||||||
guint buffer_full_id;
|
guint buffer_full_id;
|
||||||
MMSerialPort *serial;
|
MMSerialPort *serial;
|
||||||
|
|
||||||
/* ---- AT probing specific context ---- */
|
/* ---- AT probing specific context ---- */
|
||||||
|
|
||||||
|
GCancellable *at_probing_cancellable;
|
||||||
|
/* Send delay for AT commands */
|
||||||
guint64 at_send_delay;
|
guint64 at_send_delay;
|
||||||
/* Number of times we tried to open the AT port */
|
/* Number of times we tried to open the AT port */
|
||||||
guint at_open_tries;
|
guint at_open_tries;
|
||||||
@@ -82,6 +91,9 @@ typedef struct {
|
|||||||
/* Current AT Result processor */
|
/* Current AT Result processor */
|
||||||
void (* at_result_processor) (MMPortProbe *self,
|
void (* at_result_processor) (MMPortProbe *self,
|
||||||
GVariant *result);
|
GVariant *result);
|
||||||
|
|
||||||
|
/* ---- QMI probing specific context ---- */
|
||||||
|
MMQmiPort *qmi_port;
|
||||||
} PortProbeRunTask;
|
} PortProbeRunTask;
|
||||||
|
|
||||||
struct _MMPortProbePrivate {
|
struct _MMPortProbePrivate {
|
||||||
@@ -96,6 +108,7 @@ struct _MMPortProbePrivate {
|
|||||||
gchar *vendor;
|
gchar *vendor;
|
||||||
gchar *product;
|
gchar *product;
|
||||||
gboolean is_icera;
|
gboolean is_icera;
|
||||||
|
gboolean is_qmi;
|
||||||
|
|
||||||
/* Current probing task. Only one can be available at a time */
|
/* Current probing task. Only one can be available at a time */
|
||||||
PortProbeRunTask *task;
|
PortProbeRunTask *task;
|
||||||
@@ -113,9 +126,10 @@ mm_port_probe_set_result_at (MMPortProbe *self,
|
|||||||
g_udev_device_get_subsystem (self->priv->port),
|
g_udev_device_get_subsystem (self->priv->port),
|
||||||
g_udev_device_get_name (self->priv->port));
|
g_udev_device_get_name (self->priv->port));
|
||||||
|
|
||||||
/* Also set as not a QCDM port */
|
/* Also set as not a QCDM/QMI port */
|
||||||
self->priv->is_qcdm = FALSE;
|
self->priv->is_qcdm = FALSE;
|
||||||
self->priv->flags |= MM_PORT_PROBE_QCDM;
|
self->priv->is_qmi = FALSE;
|
||||||
|
self->priv->flags |= (MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI);
|
||||||
} else {
|
} else {
|
||||||
mm_dbg ("(%s/%s) port is not AT-capable",
|
mm_dbg ("(%s/%s) port is not AT-capable",
|
||||||
g_udev_device_get_subsystem (self->priv->port),
|
g_udev_device_get_subsystem (self->priv->port),
|
||||||
@@ -199,21 +213,51 @@ mm_port_probe_set_result_qcdm (MMPortProbe *self,
|
|||||||
g_udev_device_get_subsystem (self->priv->port),
|
g_udev_device_get_subsystem (self->priv->port),
|
||||||
g_udev_device_get_name (self->priv->port));
|
g_udev_device_get_name (self->priv->port));
|
||||||
|
|
||||||
/* Also set as not an AT port */
|
/* Also set as not an AT/QMI port */
|
||||||
self->priv->is_at = FALSE;
|
self->priv->is_at = FALSE;
|
||||||
|
self->priv->is_qmi = FALSE;
|
||||||
self->priv->vendor = NULL;
|
self->priv->vendor = NULL;
|
||||||
self->priv->product = NULL;
|
self->priv->product = NULL;
|
||||||
self->priv->is_icera = FALSE;
|
self->priv->is_icera = FALSE;
|
||||||
self->priv->flags |= (MM_PORT_PROBE_AT |
|
self->priv->flags |= (MM_PORT_PROBE_AT |
|
||||||
MM_PORT_PROBE_AT_VENDOR |
|
MM_PORT_PROBE_AT_VENDOR |
|
||||||
MM_PORT_PROBE_AT_PRODUCT |
|
MM_PORT_PROBE_AT_PRODUCT |
|
||||||
MM_PORT_PROBE_AT_ICERA);
|
MM_PORT_PROBE_AT_ICERA |
|
||||||
|
MM_PORT_PROBE_QMI);
|
||||||
} else
|
} else
|
||||||
mm_dbg ("(%s/%s) port is not QCDM-capable",
|
mm_dbg ("(%s/%s) port is not QCDM-capable",
|
||||||
g_udev_device_get_subsystem (self->priv->port),
|
g_udev_device_get_subsystem (self->priv->port),
|
||||||
g_udev_device_get_name (self->priv->port));
|
g_udev_device_get_name (self->priv->port));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_port_probe_set_result_qmi (MMPortProbe *self,
|
||||||
|
gboolean qmi)
|
||||||
|
{
|
||||||
|
self->priv->is_qmi = qmi;
|
||||||
|
self->priv->flags |= MM_PORT_PROBE_QMI;
|
||||||
|
|
||||||
|
if (self->priv->is_qmi) {
|
||||||
|
mm_dbg ("(%s/%s) port is QMI-capable",
|
||||||
|
g_udev_device_get_subsystem (self->priv->port),
|
||||||
|
g_udev_device_get_name (self->priv->port));
|
||||||
|
|
||||||
|
/* Also set as not an AT/QCDM port */
|
||||||
|
self->priv->is_at = FALSE;
|
||||||
|
self->priv->is_qcdm = 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);
|
||||||
|
} 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));
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean serial_probe_at (MMPortProbe *self);
|
static gboolean serial_probe_at (MMPortProbe *self);
|
||||||
static gboolean serial_probe_qcdm (MMPortProbe *self);
|
static gboolean serial_probe_qcdm (MMPortProbe *self);
|
||||||
static void serial_probe_schedule (MMPortProbe *self);
|
static void serial_probe_schedule (MMPortProbe *self);
|
||||||
@@ -233,6 +277,12 @@ port_probe_run_task_free (PortProbeRunTask *task)
|
|||||||
g_object_unref (task->serial);
|
g_object_unref (task->serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task->qmi_port) {
|
||||||
|
if (mm_qmi_port_is_open (task->qmi_port))
|
||||||
|
mm_qmi_port_close (task->qmi_port);
|
||||||
|
g_object_unref (task->qmi_port);
|
||||||
|
}
|
||||||
|
|
||||||
if (task->cancellable)
|
if (task->cancellable)
|
||||||
g_object_unref (task->cancellable);
|
g_object_unref (task->cancellable);
|
||||||
if (task->at_probing_cancellable)
|
if (task->at_probing_cancellable)
|
||||||
@@ -288,6 +338,55 @@ port_probe_run_is_cancelled (MMPortProbe *self)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qmi_port_open_ready (MMQmiPort *qmi_port,
|
||||||
|
GAsyncResult *res,
|
||||||
|
MMPortProbe *self)
|
||||||
|
{
|
||||||
|
PortProbeRunTask *task = self->priv->task;
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean is_qmi;
|
||||||
|
|
||||||
|
is_qmi = mm_qmi_port_open_finish (qmi_port, res, &error);
|
||||||
|
if (!is_qmi) {
|
||||||
|
mm_dbg ("(%s/%s) error checking QMI 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_qmi (self, is_qmi);
|
||||||
|
|
||||||
|
mm_qmi_port_close (qmi_port);
|
||||||
|
|
||||||
|
/* All done! Finish asynchronously */
|
||||||
|
port_probe_run_task_complete (task, TRUE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
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;
|
||||||
|
|
||||||
|
mm_dbg ("(%s/%s) probing QMI...",
|
||||||
|
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->qmi_port = mm_qmi_port_new (g_udev_device_get_name (self->priv->port));
|
||||||
|
mm_qmi_port_open (task->qmi_port,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)qmi_port_open_ready,
|
||||||
|
self);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
|
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
|
||||||
GByteArray *response,
|
GByteArray *response,
|
||||||
@@ -957,7 +1056,7 @@ mm_port_probe_run (MMPortProbe *self,
|
|||||||
/* Check if we already have the requested probing results.
|
/* Check if we already have the requested probing results.
|
||||||
* We will fix here the 'task->flags' so that we only request probing
|
* We will fix here the 'task->flags' so that we only request probing
|
||||||
* for the missing things. */
|
* for the missing things. */
|
||||||
for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_QCDM; i = (i << 1)) {
|
for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_QMI; i = (i << 1)) {
|
||||||
if ((flags & i) && !(self->priv->flags & i)) {
|
if ((flags & i) && !(self->priv->flags & i)) {
|
||||||
task->flags += i;
|
task->flags += i;
|
||||||
}
|
}
|
||||||
@@ -993,12 +1092,18 @@ mm_port_probe_run (MMPortProbe *self,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, start by opening as QCDM port */
|
/* If QCDM probing needed, start by opening as QCDM port */
|
||||||
if (task->flags & MM_PORT_PROBE_QCDM) {
|
if (task->flags & MM_PORT_PROBE_QCDM) {
|
||||||
task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self);
|
task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self);
|
||||||
return;
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Shouldn't happen */
|
/* Shouldn't happen */
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
@@ -1058,6 +1163,24 @@ mm_port_probe_is_qcdm (MMPortProbe *self)
|
|||||||
FALSE);
|
FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_port_probe_is_qmi (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_equal (subsys, "usb") ||
|
||||||
|
!name ||
|
||||||
|
!g_str_has_prefix (name, "cdc-wdm"))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return self->priv->is_qmi;
|
||||||
|
}
|
||||||
|
|
||||||
MMPortType
|
MMPortType
|
||||||
mm_port_probe_get_port_type (MMPortProbe *self)
|
mm_port_probe_get_port_type (MMPortProbe *self)
|
||||||
{
|
{
|
||||||
@@ -1073,7 +1196,8 @@ mm_port_probe_get_port_type (MMPortProbe *self)
|
|||||||
return MM_PORT_TYPE_NET;
|
return MM_PORT_TYPE_NET;
|
||||||
|
|
||||||
if (g_str_equal (subsys, "usb") &&
|
if (g_str_equal (subsys, "usb") &&
|
||||||
g_str_has_prefix (name, "cdc-wdm"))
|
g_str_has_prefix (name, "cdc-wdm") &&
|
||||||
|
self->priv->is_qmi)
|
||||||
return MM_PORT_TYPE_QMI;
|
return MM_PORT_TYPE_QMI;
|
||||||
|
|
||||||
if (self->priv->flags & MM_PORT_PROBE_QCDM &&
|
if (self->priv->flags & MM_PORT_PROBE_QCDM &&
|
||||||
|
@@ -41,6 +41,7 @@ typedef enum { /*< underscore_name=mm_port_probe_flag >*/
|
|||||||
MM_PORT_PROBE_AT_PRODUCT = 1 << 2,
|
MM_PORT_PROBE_AT_PRODUCT = 1 << 2,
|
||||||
MM_PORT_PROBE_AT_ICERA = 1 << 3,
|
MM_PORT_PROBE_AT_ICERA = 1 << 3,
|
||||||
MM_PORT_PROBE_QCDM = 1 << 4,
|
MM_PORT_PROBE_QCDM = 1 << 4,
|
||||||
|
MM_PORT_PROBE_QMI = 1 << 5
|
||||||
} MMPortProbeFlag;
|
} MMPortProbeFlag;
|
||||||
|
|
||||||
typedef struct _MMPortProbe MMPortProbe;
|
typedef struct _MMPortProbe MMPortProbe;
|
||||||
@@ -95,6 +96,8 @@ void mm_port_probe_set_result_at_icera (MMPortProbe *self,
|
|||||||
gboolean is_icera);
|
gboolean is_icera);
|
||||||
void mm_port_probe_set_result_qcdm (MMPortProbe *self,
|
void mm_port_probe_set_result_qcdm (MMPortProbe *self,
|
||||||
gboolean qcdm);
|
gboolean qcdm);
|
||||||
|
void mm_port_probe_set_result_qmi (MMPortProbe *self,
|
||||||
|
gboolean qmi);
|
||||||
|
|
||||||
/* Run probing */
|
/* Run probing */
|
||||||
void mm_port_probe_run (MMPortProbe *self,
|
void mm_port_probe_run (MMPortProbe *self,
|
||||||
@@ -115,6 +118,7 @@ gboolean mm_port_probe_run_cancel_at_probing (MMPortProbe *self);
|
|||||||
MMPortType mm_port_probe_get_port_type (MMPortProbe *self);
|
MMPortType mm_port_probe_get_port_type (MMPortProbe *self);
|
||||||
gboolean mm_port_probe_is_at (MMPortProbe *self);
|
gboolean mm_port_probe_is_at (MMPortProbe *self);
|
||||||
gboolean mm_port_probe_is_qcdm (MMPortProbe *self);
|
gboolean mm_port_probe_is_qcdm (MMPortProbe *self);
|
||||||
|
gboolean mm_port_probe_is_qmi (MMPortProbe *self);
|
||||||
const gchar *mm_port_probe_get_vendor (MMPortProbe *self);
|
const gchar *mm_port_probe_get_vendor (MMPortProbe *self);
|
||||||
const gchar *mm_port_probe_get_product (MMPortProbe *self);
|
const gchar *mm_port_probe_get_product (MMPortProbe *self);
|
||||||
gboolean mm_port_probe_is_icera (MMPortProbe *self);
|
gboolean mm_port_probe_is_icera (MMPortProbe *self);
|
||||||
|
Reference in New Issue
Block a user