[PATCH] qmi-firmware-update: support USB3->USB2 mode changes during upgrade
Dan Williams
dcbw at redhat.com
Wed Jan 17 17:44:08 UTC 2018
On Wed, 2018-01-17 at 15:02 +0100, Bjørn Mork wrote:
> 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.
Patch LGTM. Made me go look at what peer ports are and why they exist,
which was interesting.
Dan
> 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 *cancellabl
> e,
> 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 de
> vice_
>
> void qfu_udev_helper_wait_for_device (QfuUdevHelperDeviceTy
> pe device_type,
> const
> gchar *sysfs_path,
> + const
> gchar *peer_port,
> GCancellable
> *cancellable,
> GAsyncReadyCallback
> callback,
> gpointer
> user_data);
More information about the libqmi-devel
mailing list