[PATCH] qmi-firmware-update: support USB3->USB2 mode changes during upgrade
Bjørn Mork
bjorn at mork.no
Wed Jan 17 14:02:53 UTC 2018
Modems operating in USB3 SuperSpeed mode may change to
USB2 HighSpeed mode while in boot-and-hold. This changes
the USB port name, causing device matching failure.
Fix by accepting matches on both the original USB(3) port and
the "peer" USB(2) port.
With this, a Sierra Wireless EM7455 can be successfully upgraded
while connected to a USB3 port:
[qfu,utils] operating mode set successfully...
[qfu-updater] reset requested successfully...
[qfu-updater] cleaning up QMI device...
[/dev/cdc-wdm0] Releasing 'dms' client with flags 'none'...
[/dev/cdc-wdm0] Unregistered 'dms' client with ID '2'
[qfu-updater] reset requested, now waiting for TTY device...
[/dev/cdc-wdm0] Sent message...
[/dev/cdc-wdm0] Sent message (translated)...
[/dev/cdc-wdm0] Received message...
[qfu-udev] event: remove ttyUSB0
[qfu-udev] event: remove ttyUSB1
[qfu-udev] event: remove 2-6:1.1
[qfu-udev] event: remove ttyUSB2
[qfu-udev] event: remove wwan0
[qfu-udev] event: remove 2-6:1.0
[qfu-udev] event: remove 2-6:1.3
[qfu-udev] event: remove 2-6:1.2
[qfu-udev] event: remove cdc-wdm0
[qfu-udev] event: remove 2-6:1.12
[qfu-udev] event: remove 2-6:1.13
[qfu-udev] event: remove 2-6
[qfu-udev] event: add 1-6
[qfu-udev] event: add 1-6:1.0
[qfu-udev] event: add ttyUSB0
[qfu-udev] peer lookup for ttyUSB0: /sys/devices/pci0000:00/0000:00:14.0/usb1/1-0:1.0/usb1-port6 => /sys/devices/pci0000:00/0000:00:14.0/usb1/1-6
[qfu-udev] waiting device (tty) matched: ttyUSB0
[qfu-updater] TTY device found: /dev/ttyUSB0
[qfu-qdl-device] opening TTY: /dev/ttyUSB0
[qfu-qdl-device] setting terminal in raw mode...
[qfu,dload-message] sent sdp:
[qfu-qdl-device] >> 70:00:00 [3, unframed]
[qfu-qdl-device] >> 7E:70:00:00:14:46:7E [7]
[qfu-qdl-device] << 7E:0D:16:00:00:00:00:88:4D:7E [10]
[qfu-qdl-device] << 0D:16:00:00:00:00 [6, unframed]
..
[qfu-updater] no more files to download
[qfu-updater] QDL reset
[qfu,qdl-message] sent reset-req:
[qfu-qdl-device] >> 2D [1, unframed]
[qfu-qdl-device] >> 7E:2D:9F:0A:7E [5]
[qfu-updater] now waiting for cdc-wdm device...
[qfu-udev] event: remove ttyUSB0
[qfu-udev] event: remove 1-6:1.0
[qfu-udev] event: remove 1-6
[qfu-udev] event: add 2-6
[qfu-udev] event: add 2-6:1.1
[qfu-udev] event: add 2-6:1.2
[qfu-udev] event: add 2-6:1.13
[qfu-udev] event: add 2-6:1.3
[qfu-udev] event: add 2-6:1.12
[qfu-udev] event: add cdc-wdm0
[qfu-udev] waiting device (cdc-wdm) matched: cdc-wdm0
[qfu-updater] cdc-wdm device found: /dev/cdc-wdm0
[qfu-updater] waiting some time (5s) before accessing the cdc-wdm device...
[qfu-udev] event: add 2-6:1.0
[qfu-udev] event: add ttyUSB0
[qfu-udev] event: add ttyUSB2
[qfu-udev] event: add ttyUSB1
[qfu-udev] event: add wwan0
[qfu-updater] creating QMI DMS client after upgrade...
Signed-off-by: Bjørn Mork <bjorn at mork.no>
---
src/qmi-firmware-update/qfu-device-selection.c | 8 +++++++
src/qmi-firmware-update/qfu-udev-helpers.c | 33 ++++++++++++++++++++++++++
src/qmi-firmware-update/qfu-udev-helpers.h | 3 +++
3 files changed, 44 insertions(+)
diff --git a/src/qmi-firmware-update/qfu-device-selection.c b/src/qmi-firmware-update/qfu-device-selection.c
index 22c2063f444b..f3576956a346 100644
--- a/src/qmi-firmware-update/qfu-device-selection.c
+++ b/src/qmi-firmware-update/qfu-device-selection.c
@@ -42,6 +42,8 @@ struct _QfuDeviceSelectionPrivate {
#if defined WITH_UDEV
/* sysfs path */
gchar *sysfs_path;
+ /* peer port sysfs path */
+ gchar *peer_port;
/* generic udev monitor */
QfuUdevHelperGenericMonitor *monitor;
#endif
@@ -227,6 +229,7 @@ qfu_device_selection_wait_for_cdc_wdm (QfuDeviceSelection *self,
task = g_task_new (self, cancellable, callback, user_data);
qfu_udev_helper_wait_for_device (QFU_UDEV_HELPER_DEVICE_TYPE_CDC_WDM,
self->priv->sysfs_path,
+ self->priv->peer_port,
cancellable,
(GAsyncReadyCallback) wait_for_device_ready,
task);
@@ -243,6 +246,7 @@ qfu_device_selection_wait_for_tty (QfuDeviceSelection *self,
task = g_task_new (self, cancellable, callback, user_data);
qfu_udev_helper_wait_for_device (QFU_UDEV_HELPER_DEVICE_TYPE_TTY,
self->priv->sysfs_path,
+ self->priv->peer_port,
cancellable,
(GAsyncReadyCallback) wait_for_device_ready,
task);
@@ -309,6 +313,9 @@ qfu_device_selection_new (const gchar *preferred_cdc_wdm,
return NULL;
}
+ /* look for a peer port */
+ self->priv->peer_port = qfu_udev_helper_find_peer_port (self->priv->sysfs_path, error);
+
/* Initialize right away the generic udev monitor for this sysfs path */
self->priv->monitor = qfu_udev_helper_generic_monitor_new (self->priv->sysfs_path);
}
@@ -333,6 +340,7 @@ finalize (GObject *object)
if (self->priv->monitor)
qfu_udev_helper_generic_monitor_free (self->priv->monitor);
g_free (self->priv->sysfs_path);
+ g_free (self->priv->peer_port);
#endif
for (i = 0; i < QFU_UDEV_HELPER_DEVICE_TYPE_LAST; i++)
diff --git a/src/qmi-firmware-update/qfu-udev-helpers.c b/src/qmi-firmware-update/qfu-udev-helpers.c
index 7524dc5fce92..27cb89fb30e2 100644
--- a/src/qmi-firmware-update/qfu-udev-helpers.c
+++ b/src/qmi-firmware-update/qfu-udev-helpers.c
@@ -228,6 +228,22 @@ qfu_udev_helper_find_by_file_path (const gchar *path,
return sysfs_path;
}
+gchar *
+qfu_udev_helper_find_peer_port (const gchar *sysfs_path,
+ GError **error)
+{
+ gchar *tmp, *path;
+
+ tmp = g_build_filename (sysfs_path, "port", "peer", NULL);
+ path = realpath (tmp, NULL);
+ g_free (tmp);
+ if (!path)
+ return NULL;
+
+ g_debug ("[qfu-udev] peer port for '%s' found: %s", sysfs_path, path);
+ return path;
+}
+
/******************************************************************************/
static gboolean
@@ -457,6 +473,7 @@ typedef struct {
QfuUdevHelperDeviceType device_type;
GUdevClient *udev;
gchar *sysfs_path;
+ gchar *peer_port;
guint timeout_id;
gulong uevent_id;
gulong cancellable_id;
@@ -471,6 +488,7 @@ wait_for_device_context_free (WaitForDeviceContext *ctx)
g_object_unref (ctx->udev);
g_free (ctx->sysfs_path);
+ g_free (ctx->peer_port);
g_slice_free (WaitForDeviceContext, ctx);
}
@@ -496,6 +514,19 @@ handle_uevent (GUdevClient *client,
return;
file = device_matches_sysfs_and_type (device, ctx->sysfs_path, ctx->device_type);
+ if (!file && ctx->peer_port) {
+ gchar *tmp, *path;
+
+ tmp = g_build_filename (ctx->peer_port, "device", NULL);
+ path = realpath (tmp, NULL);
+ g_free (tmp);
+ if (!path)
+ return;
+
+ file = device_matches_sysfs_and_type (device, path, ctx->device_type);
+ g_debug ("[qfu-udev] peer lookup for %s: %s => %s", g_udev_device_get_name (device), ctx->peer_port, path);
+ g_free (path);
+ }
if (!file)
return;
@@ -567,6 +598,7 @@ wait_for_device_cancelled (GCancellable *cancellable,
void
qfu_udev_helper_wait_for_device (QfuUdevHelperDeviceType device_type,
const gchar *sysfs_path,
+ const gchar *peer_port,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
@@ -577,6 +609,7 @@ qfu_udev_helper_wait_for_device (QfuUdevHelperDeviceType device_type,
ctx = g_slice_new0 (WaitForDeviceContext);
ctx->device_type = device_type;
ctx->sysfs_path = g_strdup (sysfs_path);
+ ctx->peer_port = g_strdup (peer_port);
if (ctx->device_type == QFU_UDEV_HELPER_DEVICE_TYPE_TTY)
ctx->udev = g_udev_client_new (tty_subsys_list);
diff --git a/src/qmi-firmware-update/qfu-udev-helpers.h b/src/qmi-firmware-update/qfu-udev-helpers.h
index 6f6eac0d1dca..552e96bd0d5c 100644
--- a/src/qmi-firmware-update/qfu-udev-helpers.h
+++ b/src/qmi-firmware-update/qfu-udev-helpers.h
@@ -42,6 +42,8 @@ gchar *qfu_udev_helper_find_by_file (GFile *file,
GError **error);
gchar *qfu_udev_helper_find_by_file_path (const gchar *path,
GError **error);
+gchar *qfu_udev_helper_find_peer_port (const gchar *sysfs_path,
+ GError **error);
gchar *qfu_udev_helper_find_by_device_info (guint16 vid,
guint16 pid,
guint busnum,
@@ -53,6 +55,7 @@ GList *qfu_udev_helper_list_devices (QfuUdevHelperDeviceType device_
void qfu_udev_helper_wait_for_device (QfuUdevHelperDeviceType device_type,
const gchar *sysfs_path,
+ const gchar *peer_port,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
--
2.11.0
More information about the libqmi-devel
mailing list