diff options
author | Bjørn Mork <bjorn@mork.no> | 2018-01-17 15:02:53 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2018-01-20 11:31:23 +0100 |
commit | 00b9856073476a80f0b7cf4cc79138bc27695ae5 (patch) | |
tree | ded0f4c3a72b4022d9035ff6093e6d4129f5edc0 | |
parent | bd2f61d7ef83ed2216e57ca2c82282b3b82071b5 (diff) |
qmi-firmware-update: support USB3->USB2 mode changes during upgrade
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@mork.no>
-rw-r--r-- | src/qmi-firmware-update/qfu-device-selection.c | 8 | ||||
-rw-r--r-- | src/qmi-firmware-update/qfu-udev-helpers.c | 33 | ||||
-rw-r--r-- | src/qmi-firmware-update/qfu-udev-helpers.h | 3 |
3 files changed, 44 insertions, 0 deletions
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); |