aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-06-27 13:57:34 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-08-29 17:14:47 +0200
commitdb99f340c89f589784a76879bcf3735c8317cfc7 (patch)
tree28fa37e8f3e74bd03fccfe684ef79d0e07eb0e5d
parent3e251129c2f2d481e3391d64db9fc12820899803 (diff)
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.
-rw-r--r--src/mm-plugin.c38
-rw-r--r--src/mm-port-probe.c140
-rw-r--r--src/mm-port-probe.h4
3 files changed, 157 insertions, 25 deletions
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index ef0453bf..8948e96c 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -589,10 +589,8 @@ mm_plugin_supports_port (MMPlugin *self,
g_udev_device_get_subsystem (port),
g_udev_device_get_name (port));
- /* Before launching any probing, check if the port is a net OR a wdm device
- * (which cannot be probed). */
- if (g_str_equal (g_udev_device_get_subsystem (port), "net") ||
- g_str_equal (g_udev_device_get_subsystem (port), "cdc-wdm")) {
+ /* Before launching any probing, check if the port is a net device. */
+ if (g_str_equal (g_udev_device_get_subsystem (port), "net")) {
g_simple_async_result_set_op_res_gpointer (
async_result,
GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED),
@@ -602,19 +600,25 @@ mm_plugin_supports_port (MMPlugin *self,
}
/* Build flags depending on what probing needed */
- probe_run_flags = MM_PORT_PROBE_NONE;
- if (self->priv->at)
- probe_run_flags |= MM_PORT_PROBE_AT;
- else if (self->priv->single_at)
- probe_run_flags |= MM_PORT_PROBE_AT;
- if (need_vendor_probing)
- probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_VENDOR);
- if (need_product_probing)
- probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_PRODUCT);
- if (self->priv->qcdm)
- probe_run_flags |= MM_PORT_PROBE_QCDM;
- 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);
+ if (!g_str_has_prefix (g_udev_device_get_name (port), "cdc-wdm")) {
+ /* Serial ports... */
+ probe_run_flags = MM_PORT_PROBE_NONE;
+ if (self->priv->at)
+ probe_run_flags |= MM_PORT_PROBE_AT;
+ else if (self->priv->single_at)
+ probe_run_flags |= MM_PORT_PROBE_AT;
+ if (need_vendor_probing)
+ probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_VENDOR);
+ if (need_product_probing)
+ probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_PRODUCT);
+ if (self->priv->qcdm)
+ probe_run_flags |= MM_PORT_PROBE_QCDM;
+ 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);
+ } else {
+ /* cdc-wdm ports... */
+ probe_run_flags = MM_PORT_PROBE_QMI;
+ }
g_assert (probe_run_flags != MM_PORT_PROBE_NONE);
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index 9c374a55..99306970 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -24,6 +24,7 @@
#include "mm-port-probe.h"
#include "mm-log.h"
+#include "mm-qmi-port.h"
#include "mm-at-serial-port.h"
#include "mm-serial-port.h"
#include "mm-serial-parsers.h"
@@ -44,6 +45,8 @@
* |----> Is Icera?
* ----> QCDM Serial Open
* |----> QCDM?
+ * ----> QMI Device Open
+ * |----> QMI Version Info check
*/
G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT)
@@ -59,15 +62,21 @@ static GParamSpec *properties[PROP_LAST];
typedef struct {
/* ---- Generic task context ---- */
+
GSimpleAsyncResult *result;
GCancellable *cancellable;
- GCancellable *at_probing_cancellable;
guint32 flags;
guint source_id;
+
+ /* ---- Serial probing specific context ---- */
+
guint buffer_full_id;
MMSerialPort *serial;
/* ---- AT probing specific context ---- */
+
+ GCancellable *at_probing_cancellable;
+ /* Send delay for AT commands */
guint64 at_send_delay;
/* Number of times we tried to open the AT port */
guint at_open_tries;
@@ -82,6 +91,9 @@ typedef struct {
/* Current AT Result processor */
void (* at_result_processor) (MMPortProbe *self,
GVariant *result);
+
+ /* ---- QMI probing specific context ---- */
+ MMQmiPort *qmi_port;
} PortProbeRunTask;
struct _MMPortProbePrivate {
@@ -96,6 +108,7 @@ struct _MMPortProbePrivate {
gchar *vendor;
gchar *product;
gboolean is_icera;
+ gboolean is_qmi;
/* Current probing task. Only one can be available at a time */
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_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->flags |= MM_PORT_PROBE_QCDM;
+ self->priv->is_qmi = FALSE;
+ self->priv->flags |= (MM_PORT_PROBE_QCDM | MM_PORT_PROBE_QMI);
} else {
mm_dbg ("(%s/%s) port is not AT-capable",
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_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_qmi = FALSE;
self->priv->vendor = NULL;
self->priv->product = NULL;
self->priv->is_icera = FALSE;
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_AT_ICERA |
+ MM_PORT_PROBE_QMI);
} else
mm_dbg ("(%s/%s) port is not QCDM-capable",
g_udev_device_get_subsystem (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_qcdm (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);
}
+ 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)
g_object_unref (task->cancellable);
if (task->at_probing_cancellable)
@@ -289,6 +339,55 @@ port_probe_run_is_cancelled (MMPortProbe *self)
}
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
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
GByteArray *response,
GError *error,
@@ -957,7 +1056,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_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)) {
task->flags += i;
}
@@ -993,12 +1092,18 @@ mm_port_probe_run (MMPortProbe *self,
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) {
task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, 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);
+ return;
+ }
+
/* Shouldn't happen */
g_assert_not_reached ();
}
@@ -1058,6 +1163,24 @@ mm_port_probe_is_qcdm (MMPortProbe *self)
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
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;
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;
if (self->priv->flags & MM_PORT_PROBE_QCDM &&
diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h
index 93b71c84..7f3db2bb 100644
--- a/src/mm-port-probe.h
+++ b/src/mm-port-probe.h
@@ -41,6 +41,7 @@ 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
} MMPortProbeFlag;
typedef struct _MMPortProbe MMPortProbe;
@@ -95,6 +96,8 @@ void mm_port_probe_set_result_at_icera (MMPortProbe *self,
gboolean is_icera);
void mm_port_probe_set_result_qcdm (MMPortProbe *self,
gboolean qcdm);
+void mm_port_probe_set_result_qmi (MMPortProbe *self,
+ gboolean qmi);
/* Run probing */
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);
gboolean mm_port_probe_is_at (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_product (MMPortProbe *self);
gboolean mm_port_probe_is_icera (MMPortProbe *self);