[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