diff options
author | Alexander Tsoy <alexander@tsoy.me> | 2017-08-11 02:36:14 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-08-06 12:48:10 +0200 |
commit | f7f530181461aaf6afa0b3f0be4d239dea410896 (patch) | |
tree | 7b797fc4e4c43f715f49af94585dede1323cdaa7 /sound | |
parent | c1ae5e7f057beb1daa72831ab22ec06e71669af7 (diff) |
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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/stream.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 963d425004f8..fc3e9fcfbc38 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -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; +} + |