]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ALSA: usb-audio: set the interface format after resume on Dell WD19
authorHui Wang <hui.wang@canonical.com>
Wed, 25 Dec 2019 03:40:00 +0000 (04:40 +0100)
committerMarcelo Henrique Cerri <marcelo.cerri@canonical.com>
Fri, 17 Jan 2020 17:23:09 +0000 (14:23 -0300)
BugLink: https://bugs.launchpad.net/bugs/1857496
Recently we found the headset-mic on the Dell Dock WD19 doesn't work
anymore after s3 (s2i or deep), this problem could be workarounded by
closing (pcm_close) the app and then reopening (pcm_open) the app, so
this bug is not easy to be detected by users.

When problem happens, retire_capture_urb() could still be called
periodically, but the size of captured data is always 0, it could be
a firmware bug on the dock. Anyway I found after resuming, the
snd_usb_pcm_prepare() will be called, and if we forcibly run
set_format() to set the interface and its endpoint, the capture
size will be normal again. This problem and workaound also apply to
playback.

To fix it in the kernel, add a quirk to let set_format() run
forcibly once after resume.

Signed-off-by: Hui Wang <hui.wang@canonical.com>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20191218132650.6303-1-hui.wang@canonical.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
(backported from commit 92adc96f8eecd9522a907c197cc3d62e405539fe)
Signed-off-by: Hui Wang <hui.wang@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Acked-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
sound/usb/card.h
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h

index ed87cc83eb47dab3134ac1a673f257c643d739a8..d127a16b9cb1558d783743b5e8f03f7d3e115e73 100644 (file)
@@ -139,6 +139,7 @@ struct snd_usb_substream {
        struct snd_usb_endpoint *sync_endpoint;
        unsigned long flags;
        bool need_setup_ep;             /* (re)configure EP at prepare? */
+       bool need_setup_fmt;            /* (re)configure fmt after resume? */
        unsigned int speed;             /* USB_SPEED_XXX */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
index ff38fca1781b6ef30fce456d15dae594db920295..1c540c0447e61df1e00e295ccc84fb911acfbe03 100644 (file)
@@ -520,11 +520,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting))
                return -EINVAL;
 
-       if (fmt == subs->cur_audiofmt)
+       if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt)
                return 0;
 
        /* close the old interface */
-       if (subs->interface >= 0 && subs->interface != fmt->iface) {
+       if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) {
                err = usb_set_interface(subs->dev, subs->interface, 0);
                if (err < 0) {
                        dev_err(&dev->dev,
@@ -536,6 +536,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                subs->altset_idx = 0;
        }
 
+       if (subs->need_setup_fmt)
+               subs->need_setup_fmt = false;
+
        /* set interface */
        if (subs->interface != fmt->iface ||
            subs->altset_idx != fmt->altset_idx) {
@@ -1670,6 +1673,13 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
                subs->data_endpoint->retire_data_urb = retire_playback_urb;
                subs->running = 0;
                return 0;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (subs->stream->chip->setup_fmt_after_resume_quirk) {
+                       stop_endpoints(subs, true);
+                       subs->need_setup_fmt = true;
+                       return 0;
+               }
+               break;
        }
 
        return -EINVAL;
@@ -1702,6 +1712,13 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
                subs->data_endpoint->retire_data_urb = retire_capture_urb;
                subs->running = 1;
                return 0;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (subs->stream->chip->setup_fmt_after_resume_quirk) {
+                       stop_endpoints(subs, true);
+                       subs->need_setup_fmt = true;
+                       return 0;
+               }
+               break;
        }
 
        return -EINVAL;
index c80e905e413592fde9db29205c0f569b990dccda..a9f6586c692eaa7267b18c97689866dc3d0c33da 100644 (file)
@@ -3344,7 +3344,8 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
                .vendor_name = "Dell",
                .product_name = "WD19 Dock",
                .profile_name = "Dell-WD15-Dock",
-               .ifnum = QUIRK_NO_INTERFACE
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_SETUP_FMT_AFTER_RESUME
        }
 },
 
index 9beba399edc13412852deeaa042833eb74241365..365388542a267d7c1cc02046171abf21e109c9ec 100644 (file)
@@ -516,6 +516,16 @@ static int create_standard_mixer_quirk(struct snd_usb_audio *chip,
        return snd_usb_create_mixer(chip, quirk->ifnum, 0);
 }
 
+
+static int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip,
+                                      struct usb_interface *iface,
+                                      struct usb_driver *driver,
+                                      const struct snd_usb_audio_quirk *quirk)
+{
+       chip->setup_fmt_after_resume_quirk = 1;
+       return 1;       /* Continue with creating streams and mixer */
+}
+
 /*
  * audio-interface quirks
  *
@@ -554,6 +564,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
                [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
                [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
+               [QUIRK_SETUP_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk,
        };
 
        if (quirk->type < QUIRK_TYPE_COUNT) {
index 419b5f5b60c4492b0d4f5d612161d7e33d921d33..77ece2fef1e3634a6b6d538e76b38555093e484d 100644 (file)
@@ -44,7 +44,7 @@ struct snd_usb_audio {
        wait_queue_head_t shutdown_wait;
        unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
        unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
-       
+       unsigned int setup_fmt_after_resume_quirk:1; /* setup the format to interface after resume */
        int num_interfaces;
        int num_suspended_intf;
        int sample_rate_read_error;
@@ -102,6 +102,7 @@ enum quirk_type {
        QUIRK_AUDIO_EDIROL_UAXX,
        QUIRK_AUDIO_ALIGN_TRANSFER,
        QUIRK_AUDIO_STANDARD_MIXER,
+       QUIRK_SETUP_FMT_AFTER_RESUME,
 
        QUIRK_TYPE_COUNT
 };