[alsa-devel] [PATCH] ALSA: usb-audio: set the interface format after resume on Dell WD19
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 closeing (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 --- sound/usb/card.h | 1 + sound/usb/pcm.c | 21 +++++++++++++++++++-- sound/usb/quirks-table.h | 3 ++- sound/usb/quirks.c | 11 +++++++++++ sound/usb/usbaudio.h | 3 ++- 5 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/sound/usb/card.h b/sound/usb/card.h index 2991b9986f66..395403a2d33f 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -145,6 +145,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) */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8a52996041e9..4ac571b2e9a6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -523,11 +523,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)) { if (!subs->stream->chip->keep_iface) { err = usb_set_interface(subs->dev, subs->interface, 0); if (err < 0) { @@ -541,6 +541,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 (iface->cur_altsetting != alts) { err = snd_usb_select_mode_quirk(subs, fmt); @@ -1734,6 +1737,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; @@ -1766,6 +1776,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; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 70c338f3ae24..d187aa6d50db 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3466,7 +3466,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 } }, /* MOTU Microbook II */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 349e1e52996d..a81c2066499f 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -508,6 +508,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 * @@ -546,6 +556,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) { diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index ff3cbf653de8..6fe3ab582ec6 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -33,7 +33,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; @@ -98,6 +98,7 @@ enum quirk_type { QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_AUDIO_STANDARD_MIXER, + QUIRK_SETUP_FMT_AFTER_RESUME,
QUIRK_TYPE_COUNT };
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
Takashi
Hi Hui and Takashi,
On Dec 19, 2019, at 3:06 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
I am not entirely sure it’s a kernel bug. [1] [2] can also fix the issue.
Since USB audio doesn’t have SNDRV_PCM_INFO_RESUME capability, userspace shouldn’t try to use snd_pcm_resume(). Commit [1] uses snd_pcm_drop() to make the device leave suspended state and the device behaves correctly with the fix.
[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/f7b3537bbf9a6916... [2] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/734a00c849815a45...
Kai-Heng
Takashi _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On 2019/12/19 下午12:55, Kai Heng Feng wrote:
Hi Hui and Takashi,
On Dec 19, 2019, at 3:06 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
I am not entirely sure it’s a kernel bug. [1] [2] can also fix the issue.
Since USB audio doesn’t have SNDRV_PCM_INFO_RESUME capability, userspace shouldn’t try to use snd_pcm_resume(). Commit [1] uses snd_pcm_drop() to make the device leave suspended state and the device behaves correctly with the fix.
[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/f7b3537bbf9a6916... [2] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/734a00c849815a45...
Thanks for sharing the info, [1] could workaround this bug because it finally called pcm_close() and pcm_open(), [2] doesn't change the executing path in th PA, it is a cosmetic improvement for [1].
I guess it is a firmware problem, and could be fixed in the kernel. Because I tested many other usb audio cards, they don't need workaroud of [1], they all could playback and capture after resuming, so this problem is specific to this hardware. And in theory a device should work same before and after suspend, it should not depend on userspace to close it and reopen it. After adding this fix, this usb audio card could work after resuming even on a system without PA. And this kernel patch doesn't have any conflict with [1]/[2] in the PA, they could work well together.
Thanks,
Hui.
Kai-Heng
Takashi _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Dec 19, 2019, at 2:23 PM, Hui Wang hui.wang@canonical.com wrote:
On 2019/12/19 下午12:55, Kai Heng Feng wrote:
Hi Hui and Takashi,
On Dec 19, 2019, at 3:06 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
I am not entirely sure it’s a kernel bug. [1] [2] can also fix the issue.
Since USB audio doesn’t have SNDRV_PCM_INFO_RESUME capability, userspace shouldn’t try to use snd_pcm_resume(). Commit [1] uses snd_pcm_drop() to make the device leave suspended state and the device behaves correctly with the fix.
[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/f7b3537bbf9a6916... [2] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/734a00c849815a45...
Thanks for sharing the info, [1] could workaround this bug because it finally called pcm_close() and pcm_open(), [2] doesn't change the executing path in th PA, it is a cosmetic improvement for [1].
In [2], if PCM doesn't support hardware resume, like USB audio, it falls through to default and calls snd_pcm_drop() to let device leave suspended state. So it’s more than a cosmetic change.
I guess it is a firmware problem, and could be fixed in the kernel. Because I tested many other usb audio cards, they don't need workaroud of [1], they all could playback and capture after resuming, so this problem is specific to this hardware. And in theory a device should work same before and after suspend, it should not depend on userspace to close it and reopen it. After adding this fix, this usb audio card could work after resuming even on a system without PA. And this kernel patch doesn't have any conflict with [1]/[2] in the PA, they could work well together.
Yes the two approaches are orthogonal in some sense. However if the issue can be solved by following alsa-lib's documentation, I don't think it's a kernel bug.
Kai-Heng
Thanks,
Hui.
Kai-Heng
Takashi _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Thu, 19 Dec 2019 07:37:07 +0100, Kai Heng Feng wrote:
On Dec 19, 2019, at 2:23 PM, Hui Wang hui.wang@canonical.com wrote:
On 2019/12/19 下午12:55, Kai Heng Feng wrote:
Hi Hui and Takashi,
On Dec 19, 2019, at 3:06 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
I am not entirely sure it’s a kernel bug. [1] [2] can also fix the issue.
Since USB audio doesn’t have SNDRV_PCM_INFO_RESUME capability, userspace shouldn’t try to use snd_pcm_resume(). Commit [1] uses snd_pcm_drop() to make the device leave suspended state and the device behaves correctly with the fix.
[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/f7b3537bbf9a6916... [2] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/734a00c849815a45...
Thanks for sharing the info, [1] could workaround this bug because it finally called pcm_close() and pcm_open(), [2] doesn't change the executing path in th PA, it is a cosmetic improvement for [1].
In [2], if PCM doesn't support hardware resume, like USB audio, it falls through to default and calls snd_pcm_drop() to let device leave suspended state. So it’s more than a cosmetic change.
Not really, the world is not only with PA.
The standard alsa-lib function snd_pcm_recover() just calls snd_pcm_prepare() when snd_pcm_resume() fails. That is, the stream is re-prepared and re-triggered without closing for the device that has no SNDRV_PCM_INFO_RESUME flag.
Takashi
I guess it is a firmware problem, and could be fixed in the kernel. Because I tested many other usb audio cards, they don't need workaroud of [1], they all could playback and capture after resuming, so this problem is specific to this hardware. And in theory a device should work same before and after suspend, it should not depend on userspace to close it and reopen it. After adding this fix, this usb audio card could work after resuming even on a system without PA. And this kernel patch doesn't have any conflict with [1]/[2] in the PA, they could work well together.
Yes the two approaches are orthogonal in some sense. However if the issue can be solved by following alsa-lib's documentation, I don't think it's a kernel bug.
Kai-Heng
Thanks,
Hui.
Kai-Heng
Takashi _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Dec 19, 2019, at 4:35 PM, Takashi Iwai tiwai@suse.de wrote:
On Thu, 19 Dec 2019 07:37:07 +0100, Kai Heng Feng wrote:
On Dec 19, 2019, at 2:23 PM, Hui Wang hui.wang@canonical.com wrote:
On 2019/12/19 下午12:55, Kai Heng Feng wrote:
Hi Hui and Takashi,
On Dec 19, 2019, at 3:06 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 18 Dec 2019 14:26:50 +0100, Hui Wang wrote:
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 closeing (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
Thanks, the workaround looks reasonable. I applied it now with Cc to stable.
I am not entirely sure it’s a kernel bug. [1] [2] can also fix the issue.
Since USB audio doesn’t have SNDRV_PCM_INFO_RESUME capability, userspace shouldn’t try to use snd_pcm_resume(). Commit [1] uses snd_pcm_drop() to make the device leave suspended state and the device behaves correctly with the fix.
[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/f7b3537bbf9a6916... [2] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/commit/734a00c849815a45...
Thanks for sharing the info, [1] could workaround this bug because it finally called pcm_close() and pcm_open(), [2] doesn't change the executing path in th PA, it is a cosmetic improvement for [1].
In [2], if PCM doesn't support hardware resume, like USB audio, it falls through to default and calls snd_pcm_drop() to let device leave suspended state. So it’s more than a cosmetic change.
Not really, the world is not only with PA.
The standard alsa-lib function snd_pcm_recover() just calls snd_pcm_prepare() when snd_pcm_resume() fails. That is, the stream is re-prepared and re-triggered without closing for the device that has no SNDRV_PCM_INFO_RESUME flag.
Understood, so that's indeed a kernel bug.
Kai-Heng
Takashi
I guess it is a firmware problem, and could be fixed in the kernel. Because I tested many other usb audio cards, they don't need workaroud of [1], they all could playback and capture after resuming, so this problem is specific to this hardware. And in theory a device should work same before and after suspend, it should not depend on userspace to close it and reopen it. After adding this fix, this usb audio card could work after resuming even on a system without PA. And this kernel patch doesn't have any conflict with [1]/[2] in the PA, they could work well together.
Yes the two approaches are orthogonal in some sense. However if the issue can be solved by following alsa-lib's documentation, I don't think it's a kernel bug.
Kai-Heng
Thanks,
Hui.
Kai-Heng
Takashi _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
participants (3)
-
Hui Wang
-
Kai Heng Feng
-
Takashi Iwai