summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2018-01-17 15:02:53 +0100
committerAleksander Morgado <aleksander@aleksander.es>2018-01-20 11:31:23 +0100
commit00b9856073476a80f0b7cf4cc79138bc27695ae5 (patch)
treeded0f4c3a72b4022d9035ff6093e6d4129f5edc0
parentbd2f61d7ef83ed2216e57ca2c82282b3b82071b5 (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.c8
-rw-r--r--src/qmi-firmware-update/qfu-udev-helpers.c33
-rw-r--r--src/qmi-firmware-update/qfu-udev-helpers.h3
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);