aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEldad Zack <eldad@fogrefinery.com>2013-04-03 17:18:58 -0400
committerTakashi Iwai <tiwai@suse.de>2013-04-04 02:32:07 -0400
commit1dc669fed61a4ec4270a89e5fb3535802cc45668 (patch)
tree437f2fbd3f8b88f94ef862305cf837a04f23aef3
parent027bbc15460d68fc8a04d9be03856e2cdb913157 (diff)
ALSA: usb-audio: UAC2: support read-only freq control
Some clocks might be read-only, e.g., external clocks (see also UAC2 4.7.2.1). In this case, setting the sample frequency will always fail (even if the rate is equal to the current clock rate), therefore do not write, but read the value and compare to the requested rate. If the clock is read only, avoid reading it twice. If it doesn't match, return -ENXIO since the clock is invalid for this configuration. Signed-off-by: Eldad Zack <eldad@fogrefinery.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/clock.c37
1 files changed, 26 insertions, 11 deletions
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index a694e1c42fdf..ae35e7d22e73 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -347,6 +347,8 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
347 __le32 data; 347 __le32 data;
348 int err, cur_rate, prev_rate; 348 int err, cur_rate, prev_rate;
349 int clock; 349 int clock;
350 bool writeable;
351 struct uac_clock_source_descriptor *cs_desc;
350 352
351 clock = snd_usb_clock_find_source(chip, fmt->clock, true); 353 clock = snd_usb_clock_find_source(chip, fmt->clock, true);
352 if (clock < 0) 354 if (clock < 0)
@@ -354,20 +356,33 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
354 356
355 prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); 357 prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
356 358
357 data = cpu_to_le32(rate); 359 cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
358 if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 360 writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1);
359 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 361 if (writeable) {
360 UAC2_CS_CONTROL_SAM_FREQ << 8, 362 data = cpu_to_le32(rate);
361 snd_usb_ctrl_intf(chip) | (clock << 8), 363 err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
362 &data, sizeof(data))) < 0) { 364 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
363 snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n", 365 UAC2_CS_CONTROL_SAM_FREQ << 8,
364 dev->devnum, iface, fmt->altsetting, rate, err); 366 snd_usb_ctrl_intf(chip) | (clock << 8),
365 return err; 367 &data, sizeof(data));
366 } 368 if (err < 0) {
369 snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n",
370 dev->devnum, iface, fmt->altsetting, rate, err);
371 return err;
372 }
367 373
368 cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); 374 cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
375 } else {
376 cur_rate = prev_rate;
377 }
369 378
370 if (cur_rate != rate) { 379 if (cur_rate != rate) {
380 if (!writeable) {
381 snd_printk(KERN_WARNING
382 "%d:%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
383 dev->devnum, iface, fmt->altsetting, rate, cur_rate);
384 return -ENXIO;
385 }
371 snd_printd(KERN_WARNING 386 snd_printd(KERN_WARNING
372 "current rate %d is different from the runtime rate %d\n", 387 "current rate %d is different from the runtime rate %d\n",
373 cur_rate, rate); 388 cur_rate, rate);