ALSA: usb-audio: work around corrupted TEAC UD-H01 feedback data
PATCH v2 1/1 ALSA: usb-audio: work around corrupted TEAC UD-H01 feedback data
From: Clemens Ladisch <[email protected]>
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.
[[email protected]: use sender->udh01_fb_quirk rather than
ep->udh01_fb_quirk in snd_usb_handle_sync_urb()]
---
Clemens, I hope you're ok that I resend this patch. With Mick's minor amendment (use sender->udh01_fb_quirk rather than ep->udh01_fb_quirk), Andrea Messa also reported success with the same hardware model.
Thanks,
Daniel
sound/usb/card.h | 1 + sound/usb/endpoint.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-)
sound/usb/card.h +1 -0
@@ -92,6 +92,7 @@ struct snd_usb_endpoint {unsigned int curframesize;/* current packet size in frames (for capture) */ unsigned int syncmaxsize;/* sync endpoint packet size */ unsigned int fill_max:1; /* fill max packet size always */ + unsigned int udh01_fb_quirk:1; /* corrupted feedback data */unsigned int datainterval;/* log_2 of data packet interval */ unsigned int syncinterval;/* P for adaptive mode, 0 otherwise */ unsigned char silence_value;
sound/usb/endpoint.c +14 -1
@@ -471,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, ep->syncinterval =3 ; ep->syncmaxsize =le16_to_cpu (get_endpoint (alts,1 )->wMaxPacketSize); + +if (chip->usb_id ==USB_ID (0x0644 ,0x8038 )/* TEAC UD-H01 */ && + ep->syncmaxsize ==4 ) + ep->udh01_fb_quirk =1 ; }list_add_tail (&ep->list, &chip->ep_list);
@@ -1105,7 +1109,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,if (f ==0 )return ; -if (unlikely (ep->freqshift ==INT_MIN )) { +if (unlikely (sender->udh01_fb_quirk)) { +/* +* The TEAC UD-H01 firmware sometimes changes the feedback value +* by +/- 0x1.0000. +*/ +if (f < ep->freqn -0x8000 ) + f +=0x10000 ; +else if (f > ep->freqn +0x8000 ) + f -=0x10000 ; + }else if (unlikely (ep->freqshift ==INT_MIN )) {/* * The first time we see a feedback value, determine its format * by shifting it left or right until it matches the nominal
Signature · 1 line
1.9.0
Takashi Iwai
AppliedAt Thu, 1 May 2014 12:20:22 +0200,
Quoted 12 lines · Daniel Mack
From: Clemens Ladisch <[email protected]>
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 <[email protected]>[[email protected]: use
sender->udh01_fb_quirkrather than
ep->udh01_fb_quirkinsnd_usb_handle_sync_urb()]
Quoted 7 lines
Reported-and-tested-by Mick <[email protected]>Reported-and-tested-by Andrea Messa <[email protected]>Cc <[email protected]>---
Clemens, I hope you're ok that I resend this patch. With Mick's minor amendment (usesender->udh01_fb_quirkrather thanep->udh01_fb_quirk), Andrea Messa also reported success with the same hardware model.
Thanks, applied now.
Let me know if this gives any problems.
Takashi
Quoted 57 lines
Thanks,
Danielsound/usb/card.h | 1 + sound/usb/endpoint.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-)sound/usb/card.h +1
-0@@ -92,6 +92,7 @@ struct snd_usb_endpoint {unsigned int curframesize;/* current packet size in frames (for capture) */ unsigned int syncmaxsize;/* sync endpoint packet size */ unsigned int fill_max:1; /* fill max packet size always */ + unsigned int udh01_fb_quirk:1; /* corrupted feedback data */unsigned int datainterval;/* log_2 of data packet interval */ unsigned int syncinterval;/* P for adaptive mode, 0 otherwise */ unsigned char silence_value;sound/usb/endpoint.c +14
-1@@ -471,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, ep->syncinterval =3 ; ep->syncmaxsize =le16_to_cpu (get_endpoint (alts,1 )->wMaxPacketSize); + +if (chip->usb_id ==USB_ID (0x0644 ,0x8038 )/* TEAC UD-H01 */ && + ep->syncmaxsize ==4 ) + ep->udh01_fb_quirk =1 ; }list_add_tail (&ep->list, &chip->ep_list);@@ -1105,7 +1109,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,if (f ==0 )return ; -if (unlikely (ep->freqshift ==INT_MIN )) { +if (unlikely (sender->udh01_fb_quirk)) { +/* +* The TEAC UD-H01 firmware sometimes changes the feedback value +* by +/- 0x1.0000. +*/ +if (f < ep->freqn -0x8000 ) + f +=0x10000 ; +else if (f > ep->freqn +0x8000 ) + f -=0x10000 ; + }else if (unlikely (ep->freqshift ==INT_MIN )) {/* * The first time we see a feedback value, determine its format * by shifting it left or right until it matches the nominal Signature · 1 line
1.9.0