ALSA: usb-audio: fix PCM device order

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>
This commit is contained in:
Alexander Tsoy 2017-08-11 02:36:14 +03:00 committed by Takashi Iwai
parent c1ae5e7f05
commit f7f5301814

View File

@ -1077,7 +1077,9 @@ found_clock:
return fp; 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_device *dev;
struct usb_interface *iface; 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)) else if (IS_ERR(fp))
return PTR_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); dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
if (protocol == UAC_VERSION_3) if (protocol == UAC_VERSION_3)
err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); 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; 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;
}