aboutsummaryrefslogtreecommitdiff
path: root/src/mm-port-probe.c
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 /src/mm-port-probe.c
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.
Diffstat (limited to 'src/mm-port-probe.c')
-rw-r--r--src/mm-port-probe.c140
1 files changed, 132 insertions, 8 deletions
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 &&