From 00b9856073476a80f0b7cf4cc79138bc27695ae5 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Wed, 17 Jan 2018 15:02:53 +0100 Subject: qmi-firmware-update: support USB3->USB2 mode changes during upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- 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 22c2063..f357695 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 7524dc5..27cb89f 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 6f6eac0..552e96b 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); -- cgit v1.2.3