ALSA: usb-audio: fix PCM device order
authorAlexander Tsoy <alexander@tsoy.me>
Thu, 10 Aug 2017 23:36:14 +0000 (02:36 +0300)
committerTakashi Iwai <tiwai@suse.de>
Tue, 6 Aug 2019 10:48:10 +0000 (12:48 +0200)
Some cards have alternate setting with non-PCM format as the first
altsetting in the interface descriptors. This confuses userspace, since
alsa-lib uses device 0 by default. So lets parse interfaces in two steps:
 1. Parse altsettings with PCM formats.
 2. Parse altsettings with non-PCM formats.

This fixes at least following cards:
 - Audinst HUD-mx2
 - Audinst HUD-mini

[ Adapted to 5.3 kernel by tiwai ]

Signed-off-by: Alexander Tsoy <alexander@tsoy.me>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/stream.c

index 963d425004f8a74ead59684e1e1b932907f2def1..fc3e9fcfbc3897e63fc7d48c75cb5883ddd099ad 100644 (file)
@@ -1077,7 +1077,9 @@ found_clock:
        return fp;
 }
 
-int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
+static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
+                                          int iface_no,
+                                          bool *has_non_pcm, bool non_pcm)
 {
        struct usb_device *dev;
        struct usb_interface *iface;
@@ -1178,6 +1180,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                else if (IS_ERR(fp))
                        return PTR_ERR(fp);
 
+               if (fp->fmt_type != UAC_FORMAT_TYPE_I)
+                       *has_non_pcm = true;
+               if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) {
+                       audioformat_free(fp);
+                       kfree(pd);
+                       fp = NULL;
+                       pd = NULL;
+                       continue;
+               }
+
                dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
                if (protocol == UAC_VERSION_3)
                        err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
@@ -1197,3 +1209,23 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
        return 0;
 }
 
+int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
+{
+       int err;
+       bool has_non_pcm = false;
+
+       /* parse PCM formats */
+       err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, false);
+       if (err < 0)
+               return err;
+
+       if (has_non_pcm) {
+               /* parse non-PCM formats */
+               err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, true);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+