Commit fde051cada91a1ae03eec8b8dd13b09379cf9dbf

Authored by Clemens Ladisch
Committed by Jiri Slaby
1 parent 07aac1cd8f

ALSA: usb-audio: work around corrupted TEAC UD-H01 feedback data

commit 7040b6d1febfdbd9c1595efb751d492cd2503f96 upstream.

The TEAC UD-H01 firmware sends wrong feedback frequency values, thus
causing the PC to send the samples at a wrong rate, which results in
clicks and crackles in the output.

Add a workaround to detect and fix the corruption.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
[mick37@gmx.de: use sender->udh01_fb_quirk rather than
 ep->udh01_fb_quirk in snd_usb_handle_sync_urb()]
Reported-and-tested-by: Mick <mick37@gmx.de>
Reported-and-tested-by: Andrea Messa <andr.messa@tiscali.it>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>

Showing 2 changed files with 15 additions and 1 deletions Side-by-side Diff

... ... @@ -91,6 +91,7 @@
91 91 unsigned int curframesize; /* current packet size in frames (for capture) */
92 92 unsigned int syncmaxsize; /* sync endpoint packet size */
93 93 unsigned int fill_max:1; /* fill max packet size always */
  94 + unsigned int udh01_fb_quirk:1; /* corrupted feedback data */
94 95 unsigned int datainterval; /* log_2 of data packet interval */
95 96 unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
96 97 unsigned char silence_value;
sound/usb/endpoint.c
... ... @@ -470,6 +470,10 @@
470 470 ep->syncinterval = 3;
471 471  
472 472 ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
  473 +
  474 + if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ &&
  475 + ep->syncmaxsize == 4)
  476 + ep->udh01_fb_quirk = 1;
473 477 }
474 478  
475 479 list_add_tail(&ep->list, &chip->ep_list);
... ... @@ -1078,7 +1082,16 @@
1078 1082 if (f == 0)
1079 1083 return;
1080 1084  
1081   - if (unlikely(ep->freqshift == INT_MIN)) {
  1085 + if (unlikely(sender->udh01_fb_quirk)) {
  1086 + /*
  1087 + * The TEAC UD-H01 firmware sometimes changes the feedback value
  1088 + * by +/- 0x1.0000.
  1089 + */
  1090 + if (f < ep->freqn - 0x8000)
  1091 + f += 0x10000;
  1092 + else if (f > ep->freqn + 0x8000)
  1093 + f -= 0x10000;
  1094 + } else if (unlikely(ep->freqshift == INT_MIN)) {
1082 1095 /*
1083 1096 * The first time we see a feedback value, determine its format
1084 1097 * by shifting it left or right until it matches the nominal