diff options
author | Takashi Iwai <tiwai@suse.de> | 2023-06-12 15:28:18 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-06-16 09:28:08 +0200 |
commit | 8ba61c9f6c9bdfbf9d197b0282641d24ae909778 (patch) | |
tree | 9a72e60dd5757c0b8929a64c6884017073f665a2 /sound/usb | |
parent | 297224fc0922e7385573a30c29ffdabb67f27b7d (diff) | |
download | lwn-8ba61c9f6c9bdfbf9d197b0282641d24ae909778.tar.gz lwn-8ba61c9f6c9bdfbf9d197b0282641d24ae909778.zip |
ALSA: usb-audio: Fix broken resume due to UAC3 power state
As reported in the bugzilla below, the PM resume of a UAC3 device may
fail due to the incomplete power state change, stuck at D1. The
reason is that the driver expects the full D0 power state change only
at hw_params, while the normal PCM resume procedure doesn't call
hw_params.
For fixing the bug, we add the same power state update to D0 at the
prepare callback, which is certainly called by the resume procedure.
Note that, with this change, the power state change in the hw_params
becomes almost redundant, since snd_usb_hw_params() doesn't touch the
parameters (at least it tires so). But dropping it is still a bit
risky (e.g. we have the media-driver binding), so I leave the D0 power
state change in snd_usb_hw_params() as is for now.
Fixes: a0a4959eb4e9 ("ALSA: usb-audio: Operate UAC3 Power Domains in PCM callbacks")
Cc: <stable@vger.kernel.org>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217539
Link: https://lore.kernel.org/r/20230612132818.29486-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/pcm.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index eec5232f9fb2..08bf535ed163 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -650,6 +650,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } + ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); + if (ret < 0) + goto unlock; + again: if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); |