Commit 690a863ff03d9a29ace2b752b8f802fba78a842f
Committed by
Takashi Iwai
1 parent
10250911c6
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
ALSA: usb: Work around CM6631 sample rate change bug
The C-Media CM6631 USB receiver doesn't respond to changes in sample rate while the interface is active. The same behavior is observed in other UAC2 hardware like the VIA VT1731. Reset the interface after setting the sampling frequency on sample rate changes, to ensure that the sample rate set by snd_usb_init_sample_rate() is used. Otherwise, the device will try to use the sample rate of the previous stream, causing distorted sound on sample rate changes. The reset is performed for all UAC2 devices, as it should not affect a standards compliant device, but it is only necessary for C-Media CM6631, VIA VT1731 and possibly others. Failure to read sample rate from the device is not handled as an error in set_sample_rate_v2(), as (permanent or intermittent) failure to read sample rate isn't essential for a successful sample rate set. Signed-off-by: Torstein Hegge <hegge@resisty.net> Acked-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 1 changed file with 35 additions and 10 deletions Side-by-side Diff
sound/usb/clock.c
... | ... | @@ -253,7 +253,7 @@ |
253 | 253 | { |
254 | 254 | struct usb_device *dev = chip->dev; |
255 | 255 | unsigned char data[4]; |
256 | - int err, crate; | |
256 | + int err, cur_rate, prev_rate; | |
257 | 257 | int clock = snd_usb_clock_find_source(chip, fmt->clock); |
258 | 258 | |
259 | 259 | if (clock < 0) |
... | ... | @@ -266,6 +266,19 @@ |
266 | 266 | return -ENXIO; |
267 | 267 | } |
268 | 268 | |
269 | + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
270 | + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
271 | + UAC2_CS_CONTROL_SAM_FREQ << 8, | |
272 | + snd_usb_ctrl_intf(chip) | (clock << 8), | |
273 | + data, sizeof(data)); | |
274 | + if (err < 0) { | |
275 | + snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | |
276 | + dev->devnum, iface, fmt->altsetting); | |
277 | + prev_rate = 0; | |
278 | + } else { | |
279 | + prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | |
280 | + } | |
281 | + | |
269 | 282 | data[0] = rate; |
270 | 283 | data[1] = rate >> 8; |
271 | 284 | data[2] = rate >> 16; |
272 | 285 | |
273 | 286 | |
... | ... | @@ -280,19 +293,31 @@ |
280 | 293 | return err; |
281 | 294 | } |
282 | 295 | |
283 | - if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
284 | - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
285 | - UAC2_CS_CONTROL_SAM_FREQ << 8, | |
286 | - snd_usb_ctrl_intf(chip) | (clock << 8), | |
287 | - data, sizeof(data))) < 0) { | |
296 | + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
297 | + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
298 | + UAC2_CS_CONTROL_SAM_FREQ << 8, | |
299 | + snd_usb_ctrl_intf(chip) | (clock << 8), | |
300 | + data, sizeof(data)); | |
301 | + if (err < 0) { | |
288 | 302 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", |
289 | 303 | dev->devnum, iface, fmt->altsetting); |
290 | - return err; | |
304 | + cur_rate = 0; | |
305 | + } else { | |
306 | + cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | |
291 | 307 | } |
292 | 308 | |
293 | - crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | |
294 | - if (crate != rate) | |
295 | - snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | |
309 | + if (cur_rate != rate) { | |
310 | + snd_printd(KERN_WARNING | |
311 | + "current rate %d is different from the runtime rate %d\n", | |
312 | + cur_rate, rate); | |
313 | + } | |
314 | + | |
315 | + /* Some devices doesn't respond to sample rate changes while the | |
316 | + * interface is active. */ | |
317 | + if (rate != prev_rate) { | |
318 | + usb_set_interface(dev, iface, 0); | |
319 | + usb_set_interface(dev, iface, fmt->altsetting); | |
320 | + } | |
296 | 321 | |
297 | 322 | return 0; |
298 | 323 | } |