| From 1b7ecc241a67ad6b584e071bd791a54e0cd5f097 Mon Sep 17 00:00:00 2001 |
| From: Hector Martin <marcan@marcan.st> |
| Date: Mon, 10 Aug 2020 17:24:00 +0900 |
| Subject: ALSA: usb-audio: work around streaming quirk for MacroSilicon MS2109 |
| |
| From: Hector Martin <marcan@marcan.st> |
| |
| 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 | 1 + |
| sound/usb/pcm.c | 6 ++++++ |
| sound/usb/quirks.c | 3 +++ |
| sound/usb/stream.c | 1 + |
| 4 files changed, 11 insertions(+) |
| |
| --- a/sound/usb/card.h |
| +++ b/sound/usb/card.h |
| @@ -133,6 +133,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 */ |
| |
| --- a/sound/usb/pcm.c |
| +++ b/sound/usb/pcm.c |
| @@ -1416,6 +1416,12 @@ static void retire_capture_urb(struct sn |
| // 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; |
| --- a/sound/usb/quirks.c |
| +++ b/sound/usb/quirks.c |
| @@ -1468,6 +1468,9 @@ void snd_usb_set_format_quirk(struct snd |
| 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; |
| } |
| } |
| |
| --- a/sound/usb/stream.c |
| +++ b/sound/usb/stream.c |
| @@ -94,6 +94,7 @@ static void snd_usb_init_substream(struc |
| 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); |
| |