Blob Blame History Raw
From 58cabe8715f20b7fb33431bb1f2c5bd7a438b11b Mon Sep 17 00:00:00 2001
From: Adam Goode <agoode@google.com>
Date: Wed, 18 Jul 2018 16:41:05 -0400
Subject: [PATCH] ALSA: usb-audio: Allow changing from a bad sample rate
Git-commit: 58cabe8715f20b7fb33431bb1f2c5bd7a438b11b
Patch-mainline: v4.19-rc1
References: bsc#1121278

If the audio device is externally clocked and set to a rate that does
not match the external clock, the clock will never be valid and we cannot
set the rate successfully. To fix this, allow a rate change even if
the clock is initially invalid, and validate again after the rate is
changed.

This fixes problems with MOTU UltraLite AVB hardware over USB.

Signed-off-by: Adam Goode <agoode@google.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 sound/usb/clock.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index c79749613fa6..db5e39d67a90 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -513,14 +513,28 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
 	bool writeable;
 	u32 bmControls;
 
+	/* First, try to find a valid clock. This may trigger
+	 * automatic clock selection if the current clock is not
+	 * valid.
+	 */
 	clock = snd_usb_clock_find_source(chip, fmt->protocol,
 					  fmt->clock, true);
-	if (clock < 0)
-		return clock;
+	if (clock < 0) {
+		/* We did not find a valid clock, but that might be
+		 * because the current sample rate does not match an
+		 * external clock source. Try again without validation
+		 * and we will do another validation after setting the
+		 * rate.
+		 */
+		clock = snd_usb_clock_find_source(chip, fmt->protocol,
+						  fmt->clock, false);
+		if (clock < 0)
+			return clock;
+	}
 
 	prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock);
 	if (prev_rate == rate)
-		return 0;
+		goto validation;
 
 	if (fmt->protocol == UAC_VERSION_3) {
 		struct uac3_clock_source_descriptor *cs_desc;
@@ -577,6 +591,10 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
 		snd_usb_set_interface_quirk(dev);
 	}
 
+validation:
+	/* validate clock after rate change */
+	if (!uac_clock_source_is_valid(chip, fmt->protocol, clock))
+		return -ENXIO;
 	return 0;
 }
 
-- 
2.20.1