diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-06-27 13:57:34 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-08-29 17:14:47 +0200 |
commit | db99f340c89f589784a76879bcf3735c8317cfc7 (patch) | |
tree | 28fa37e8f3e74bd03fccfe684ef79d0e07eb0e5d | |
parent | 3e251129c2f2d481e3391d64db9fc12820899803 (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.c | 38 | ||||
-rw-r--r-- | src/mm-port-probe.c | 140 | ||||
-rw-r--r-- | src/mm-port-probe.h | 4 |
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); |