Merge remote-tracking branch 'cros/upstream' into 'cros/master'
diff --git a/libmm-glib/mm-modem.c b/libmm-glib/mm-modem.c
index 3274a44..5221c2d 100644
--- a/libmm-glib/mm-modem.c
+++ b/libmm-glib/mm-modem.c
@@ -2986,6 +2986,7 @@
 
     g_mutex_clear (&self->priv->unlock_retries_mutex);
     g_mutex_clear (&self->priv->supported_modes_mutex);
+    g_mutex_clear (&self->priv->supported_capabilities_mutex);
     g_mutex_clear (&self->priv->supported_bands_mutex);
     g_mutex_clear (&self->priv->current_bands_mutex);
 
diff --git a/plugins/altair/mm-broadband-modem-altair-lte.c b/plugins/altair/mm-broadband-modem-altair-lte.c
index d313a51..b71884b 100644
--- a/plugins/altair/mm-broadband-modem-altair-lte.c
+++ b/plugins/altair/mm-broadband-modem-altair-lte.c
@@ -1402,7 +1402,7 @@
                                               MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE,
                                               MMBroadbandModemAltairLtePrivate);
 
-    self->priv->sim_refresh_regex = g_regex_new ("\\r\\n\\%NOTIFYEV:\\s*SIMREFRESH,?(\\d*)\\r+\\n",
+    self->priv->sim_refresh_regex = g_regex_new ("\\r\\n\\%NOTIFYEV:\\s*\"?SIMREFRESH\"?,?(\\d*)\\r+\\n",
                                                  G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
     self->priv->sim_refresh_detach_in_progress = FALSE;
     self->priv->sim_refresh_timer_id = 0;
diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
index 5dc4f96..7604dfa 100644
--- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c
+++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
@@ -66,6 +66,7 @@
 
     g_free (bands_str);
     g_free (expected_bands_str);
+    g_array_unref (bands);
 }
 
 static void
@@ -150,6 +151,7 @@
 
     g_free (bands_str);
     g_free (expected_bands_str);
+    g_array_unref (bands);
 }
 
 static void
diff --git a/src/77-mm-usb-device-blacklist.rules b/src/77-mm-usb-device-blacklist.rules
index 7bb894f..5076ea0 100644
--- a/src/77-mm-usb-device-blacklist.rules
+++ b/src/77-mm-usb-device-blacklist.rules
@@ -125,4 +125,7 @@
 # empiriKit science lab controller device
 ATTRS{idVendor}=="0425", ATTRS{idProduct}=="0408", ENV{ID_MM_DEVICE_IGNORE}="1"
 
+# Infineon Flashloader used by Intel XMM modem bootloader
+ATTRS{idVendor}=="8087", ATTRS{idProduct}=="0716", ENV{ID_MM_DEVICE_IGNORE}="1"
+
 LABEL="mm_usb_device_blacklist_end"
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c
index 8c2fc31..73aa749 100644
--- a/src/mm-plugin-manager.c
+++ b/src/mm-plugin-manager.c
@@ -331,6 +331,84 @@
 }
 
 static void
+suggest_single_port_probe_result (PortProbeContext *target_port_probe_ctx,
+                                  MMPlugin *suggested_plugin,
+                                  gboolean reschedule_deferred)
+{
+    gboolean forbidden_icera;
+
+    /* Plugin suggestions serve two different purposes here:
+     *  1) Finish all the probes which were deferred until suggested.
+     *  2) Suggest to other probes which plugin to test next.
+     *
+     * The exception here is when we suggest the GENERIC plugin.
+     * In this case, only purpose (1) is applied, this is, only
+     * the deferred until suggested probes get finished.
+     */
+
+    if (target_port_probe_ctx->best_plugin || target_port_probe_ctx->suggested_plugin)
+        return;
+
+    /* Complete tasks which were deferred until suggested */
+    if (target_port_probe_ctx->defer_until_suggested) {
+        /* Reset the defer until suggested flag; we consider this
+         * cancelled probe completed now. */
+        target_port_probe_ctx->defer_until_suggested = FALSE;
+
+        if (suggested_plugin) {
+            mm_dbg ("(Plugin Manager) (%s) [%s] deferred task completed, got suggested plugin",
+                    mm_plugin_get_name (suggested_plugin),
+                    g_udev_device_get_name (target_port_probe_ctx->port));
+            /* Advance to the suggested plugin and re-check support there */
+            target_port_probe_ctx->suggested_plugin = g_object_ref (suggested_plugin);
+            target_port_probe_ctx->current = g_list_find (target_port_probe_ctx->current,
+                                                          target_port_probe_ctx->suggested_plugin);
+        } else {
+            mm_dbg ("(Plugin Manager) [%s] deferred task cancelled, no suggested plugin",
+                    g_udev_device_get_name (target_port_probe_ctx->port));
+            target_port_probe_ctx->best_plugin = NULL;
+            target_port_probe_ctx->current = NULL;
+        }
+
+        /* Schedule checking support, which will end the operation */
+        if (reschedule_deferred) {
+            g_assert (target_port_probe_ctx->defer_id == 0);
+            target_port_probe_ctx->defer_id = g_idle_add ((GSourceFunc)deferred_support_check_idle,
+                                                          target_port_probe_ctx);
+        }
+        return;
+    }
+
+    /* If no plugin being suggested, done */
+    if (!suggested_plugin)
+        return;
+
+    /* The GENERIC plugin is NEVER suggested to others */
+    if (g_str_equal (mm_plugin_get_name (suggested_plugin), MM_PLUGIN_GENERIC_NAME))
+        return;
+
+    /* If the plugin has MM_PLUGIN_FORBIDDEN_ICERA set, we do *not* suggest
+     * the plugin to others. Icera devices may not reply to the icera probing
+     * in all ports, so if other ports need to be tested for icera support,
+     * they should all go on. */
+    g_object_get (suggested_plugin,
+                  MM_PLUGIN_FORBIDDEN_ICERA, &forbidden_icera,
+                  NULL);
+    if (forbidden_icera)
+        return;
+
+    /* We should *not* cancel probing in the port if the plugin being
+     * checked right now is not the one being suggested. Each port
+     * should run its probing independently, and we'll later decide
+     * which result applies to the whole device.
+     */
+    mm_dbg ("(Plugin Manager) (%s) [%s] suggested plugin for port",
+            mm_plugin_get_name (suggested_plugin),
+            g_udev_device_get_name (target_port_probe_ctx->port));
+    target_port_probe_ctx->suggested_plugin = g_object_ref (suggested_plugin);
+}
+
+static void
 suggest_port_probe_result (FindDeviceSupportContext *ctx,
                            PortProbeContext *origin,
                            MMPlugin *suggested_plugin)
@@ -340,72 +418,8 @@
     for (l = ctx->running_probes; l; l = g_list_next (l)) {
         PortProbeContext *port_probe_ctx = l->data;
 
-        /* Plugin suggestions serve two different purposes here:
-         *  1) Finish all the probes which were deferred until suggested.
-         *  2) Suggest to other probes which plugin to test next.
-         *
-         * The exception here is when we suggest the GENERIC plugin.
-         * In this case, only purpose (1) is applied, this is, only
-         * the deferred until suggested probes get finished.
-         */
-
-        if (port_probe_ctx != origin &&
-            !port_probe_ctx->best_plugin &&
-            !port_probe_ctx->suggested_plugin) {
-            /* If we got a task deferred until a suggestion comes,
-             * complete it */
-            if (port_probe_ctx->defer_until_suggested) {
-                /* Reset the defer until suggested flag; we consider this
-                 * cancelled probe completed now. */
-                port_probe_ctx->defer_until_suggested = FALSE;
-
-                if (suggested_plugin) {
-                    mm_dbg ("(Plugin Manager) (%s) [%s] deferred task completed, got suggested plugin",
-                            mm_plugin_get_name (suggested_plugin),
-                            g_udev_device_get_name (port_probe_ctx->port));
-                    /* Advance to the suggested plugin and re-check support there */
-                    port_probe_ctx->suggested_plugin = g_object_ref (suggested_plugin);
-                    port_probe_ctx->current = g_list_find (port_probe_ctx->current,
-                                                           port_probe_ctx->suggested_plugin);
-                } else {
-                    mm_dbg ("(Plugin Manager) [%s] deferred task cancelled, no suggested plugin",
-                            g_udev_device_get_name (port_probe_ctx->port));
-                    port_probe_ctx->best_plugin = NULL;
-                    port_probe_ctx->current = NULL;
-                }
-
-                /* Schedule checking support, which will end the operation */
-                g_assert (port_probe_ctx->defer_id == 0);
-                port_probe_ctx->defer_id = g_idle_add ((GSourceFunc)deferred_support_check_idle,
-                                                       port_probe_ctx);
-            }
-            /* We should *not* cancel probing in the port if the plugin being
-             * checked right now is not the one being suggested. Each port
-             * should run its probing independently, and we'll later decide
-             * which result applies to the whole device.
-             */
-            else if (suggested_plugin &&
-                     /* The GENERIC plugin is NEVER suggested to others */
-                     !g_str_equal (mm_plugin_get_name (suggested_plugin),
-                                   MM_PLUGIN_GENERIC_NAME)) {
-                gboolean forbidden_icera;
-
-                /* If the plugin has MM_PLUGIN_FORBIDDEN_ICERA set, we do *not* suggest
-                 * the plugin to others. Icera devices may not reply to the icera probing
-                 * in all ports, so if other ports need to be tested for icera support,
-                 * they should all go on. */
-                g_object_get (suggested_plugin,
-                              MM_PLUGIN_FORBIDDEN_ICERA, &forbidden_icera,
-                              NULL);
-
-                if (!forbidden_icera) {
-                    mm_dbg ("(Plugin Manager) (%s) [%s] suggested plugin for port",
-                            mm_plugin_get_name (suggested_plugin),
-                            g_udev_device_get_name (port_probe_ctx->port));
-                    port_probe_ctx->suggested_plugin = g_object_ref (suggested_plugin);
-                }
-            }
-        }
+        if (port_probe_ctx != origin)
+            suggest_single_port_probe_result (port_probe_ctx, suggested_plugin, TRUE);
     }
 }
 
@@ -508,6 +522,25 @@
 
 
     case MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED:
+        /* If we're deferred until suggested, but there is already a plugin
+         * suggested in the parent device context, grab it. This may happen if
+         * e.g. a wwan interface arrives *after* a port has already been probed.
+         */
+        if (!port_probe_ctx->suggested_plugin) {
+            MMPlugin *device_plugin;
+
+            /* Get info about the currently scheduled plugin in the device */
+            device_plugin = (MMPlugin *)mm_device_peek_plugin (port_probe_ctx->parent_ctx->device);
+            if (device_plugin) {
+                mm_dbg ("(Plugin Manager) (%s) [%s] task deferred until result suggested and got suggested plugin",
+                        mm_plugin_get_name (device_plugin),
+                        g_udev_device_get_name (port_probe_ctx->port));
+                /* Flag it as deferred before suggesting probe result */
+                port_probe_ctx->defer_until_suggested = TRUE;
+                suggest_single_port_probe_result (port_probe_ctx, device_plugin, FALSE);
+            }
+        }
+
         /* If we arrived here and we already have a plugin suggested, use it */
         if (port_probe_ctx->suggested_plugin) {
             if (port_probe_ctx->suggested_plugin == plugin) {
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index cc96261..6175a05 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -1591,8 +1591,9 @@
     GError *error = NULL;
 
     parsed = mm_3gpp_parse_iccid (raw_iccid, &error);
+    g_assert (parsed == NULL);
     g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
-    g_free (parsed);
+    g_error_free (error);
 }
 
 static void
@@ -1603,8 +1604,9 @@
     GError *error = NULL;
 
     parsed = mm_3gpp_parse_iccid (raw_iccid, &error);
+    g_assert (parsed == NULL);
     g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
-    g_free (parsed);
+    g_error_free (error);
 }
 
 static void
@@ -1615,8 +1617,9 @@
     GError *error = NULL;
 
     parsed = mm_3gpp_parse_iccid (raw_iccid, &error);
+    g_assert (parsed == NULL);
     g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
-    g_free (parsed);
+    g_error_free (error);
 }
 
 static void
@@ -1627,8 +1630,9 @@
     GError *error = NULL;
 
     parsed = mm_3gpp_parse_iccid (raw_iccid, &error);
+    g_assert (parsed == NULL);
     g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
-    g_free (parsed);
+    g_error_free (error);
 }
 
 /*****************************************************************************/
@@ -1840,6 +1844,10 @@
     g_assert (mem3->len == 2);
     g_assert (is_storage_supported (mem3, MM_SMS_STORAGE_SM));
     g_assert (is_storage_supported (mem3, MM_SMS_STORAGE_MT));
+
+    g_array_unref (mem1);
+    g_array_unref (mem2);
+    g_array_unref (mem3);
 }
 
 /*****************************************************************************/
diff --git a/src/tests/test-sms-part-3gpp.c b/src/tests/test-sms-part-3gpp.c
index dc470d7..21822f0 100644
--- a/src/tests/test-sms-part-3gpp.c
+++ b/src/tests/test-sms-part-3gpp.c
@@ -360,6 +360,7 @@
     g_assert (part == NULL);
     /* We don't care for the specific error type */
     g_assert (error != NULL);
+    g_error_free (error);
     g_free (hexpdu);
 }
 
diff --git a/src/tests/test-sms-part-cdma.c b/src/tests/test-sms-part-cdma.c
index 644de8d..17d7896 100644
--- a/src/tests/test-sms-part-cdma.c
+++ b/src/tests/test-sms-part-cdma.c
@@ -399,6 +399,7 @@
     }
 
     pdu = mm_sms_part_cdma_get_submit_pdu (part, &len, &error);
+    mm_sms_part_free (part);
 
     trace_pdu (pdu, len);