ALSA: usb-audio: work around streaming quirk for MacroSilicon MS2109
authorHector Martin <marcan@marcan.st>
Mon, 10 Aug 2020 08:24:00 +0000 (17:24 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 Aug 2020 09:02:06 +0000 (11:02 +0200)
commit 1b7ecc241a67ad6b584e071bd791a54e0cd5f097 upstream.

Further investigation of the L-R swap problem on the MS2109 reveals that
the problem isn't that the channels are swapped, but rather that they
are swapped and also out of phase by one sample. In other words, the
issue is actually that the very first frame that comes from the hardware
is a half-frame containing only the right channel, and after that
everything becomes offset.

So introduce a new quirk field to drop the very first 2 bytes that come
in after the format is configured and a capture stream starts. This puts
the channels in phase and in the correct order.

Cc: stable@vger.kernel.org
Signed-off-by: Hector Martin <marcan@marcan.st>
Link: https://lore.kernel.org/r/20200810082400.225858-1-marcan@marcan.st
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
sound/usb/card.h
sound/usb/pcm.c
sound/usb/quirks.c
sound/usb/stream.c

index 111b0f009afa493c1aab56ae7fd6c4b07b648996..f1a517ac49b28dc9e0a1e730f30ce36f9005e2bd 100644 (file)
@@ -125,6 +125,7 @@ struct snd_usb_substream {
        unsigned int tx_length_quirk:1; /* add length specifier to transfers */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
        unsigned int pkt_offset_adj;    /* Bytes to drop from beginning of packets (for non-compliant devices) */
+       unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */
 
        unsigned int running: 1;        /* running status */
 
index 9bc995f9b4e1717086df809b5b911154c8ca0ed7..ec7bea45c852cdb85c7d938ba9f83a05d673d819 100644 (file)
@@ -1312,6 +1312,12 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
                        // continue;
                }
                bytes = urb->iso_frame_desc[i].actual_length;
+               if (subs->stream_offset_adj > 0) {
+                       unsigned int adj = min(subs->stream_offset_adj, bytes);
+                       cp += adj;
+                       bytes -= adj;
+                       subs->stream_offset_adj -= adj;
+               }
                frames = bytes / stride;
                if (!subs->txfr_quirk)
                        bytes = frames * stride;
index 486d27129ac395001dc60f52628430858f8ef836..08e1af85af384587e4b2f1ac23747732403f98ad 100644 (file)
@@ -1121,6 +1121,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
                set_format_emu_quirk(subs, fmt);
                break;
+       case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
+               subs->stream_offset_adj = 2;
+               break;
        }
 }
 
index 8e9548bc1f1a922e6ceb5c99450da8ba28ee22ff..499f8def98de8ac7cfdf93564e506ae74d0d689d 100644 (file)
@@ -95,6 +95,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
        subs->tx_length_quirk = as->chip->tx_length_quirk;
        subs->speed = snd_usb_get_speed(subs->dev);
        subs->pkt_offset_adj = 0;
+       subs->stream_offset_adj = 0;
 
        snd_usb_set_pcm_ops(as->pcm, stream);