diff options
Diffstat (limited to 'sound/usb/clock.c')
-rw-r--r-- | sound/usb/clock.c | 231 |
1 files changed, 205 insertions, 26 deletions
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index eb3396ffba4c..ab39ccb974c6 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
24 | #include <linux/usb/audio.h> | 24 | #include <linux/usb/audio.h> |
25 | #include <linux/usb/audio-v2.h> | 25 | #include <linux/usb/audio-v2.h> |
26 | #include <linux/usb/audio-v3.h> | ||
26 | 27 | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/info.h> | 29 | #include <sound/info.h> |
@@ -50,6 +51,22 @@ static struct uac_clock_source_descriptor * | |||
50 | return NULL; | 51 | return NULL; |
51 | } | 52 | } |
52 | 53 | ||
54 | static struct uac3_clock_source_descriptor * | ||
55 | snd_usb_find_clock_source_v3(struct usb_host_interface *ctrl_iface, | ||
56 | int clock_id) | ||
57 | { | ||
58 | struct uac3_clock_source_descriptor *cs = NULL; | ||
59 | |||
60 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
61 | ctrl_iface->extralen, | ||
62 | cs, UAC3_CLOCK_SOURCE))) { | ||
63 | if (cs->bClockID == clock_id) | ||
64 | return cs; | ||
65 | } | ||
66 | |||
67 | return NULL; | ||
68 | } | ||
69 | |||
53 | static struct uac_clock_selector_descriptor * | 70 | static struct uac_clock_selector_descriptor * |
54 | snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, | 71 | snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, |
55 | int clock_id) | 72 | int clock_id) |
@@ -69,6 +86,22 @@ static struct uac_clock_selector_descriptor * | |||
69 | return NULL; | 86 | return NULL; |
70 | } | 87 | } |
71 | 88 | ||
89 | static struct uac3_clock_selector_descriptor * | ||
90 | snd_usb_find_clock_selector_v3(struct usb_host_interface *ctrl_iface, | ||
91 | int clock_id) | ||
92 | { | ||
93 | struct uac3_clock_selector_descriptor *cs = NULL; | ||
94 | |||
95 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
96 | ctrl_iface->extralen, | ||
97 | cs, UAC3_CLOCK_SELECTOR))) { | ||
98 | if (cs->bClockID == clock_id) | ||
99 | return cs; | ||
100 | } | ||
101 | |||
102 | return NULL; | ||
103 | } | ||
104 | |||
72 | static struct uac_clock_multiplier_descriptor * | 105 | static struct uac_clock_multiplier_descriptor * |
73 | snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, | 106 | snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, |
74 | int clock_id) | 107 | int clock_id) |
@@ -85,6 +118,22 @@ static struct uac_clock_multiplier_descriptor * | |||
85 | return NULL; | 118 | return NULL; |
86 | } | 119 | } |
87 | 120 | ||
121 | static struct uac3_clock_multiplier_descriptor * | ||
122 | snd_usb_find_clock_multiplier_v3(struct usb_host_interface *ctrl_iface, | ||
123 | int clock_id) | ||
124 | { | ||
125 | struct uac3_clock_multiplier_descriptor *cs = NULL; | ||
126 | |||
127 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
128 | ctrl_iface->extralen, | ||
129 | cs, UAC3_CLOCK_MULTIPLIER))) { | ||
130 | if (cs->bClockID == clock_id) | ||
131 | return cs; | ||
132 | } | ||
133 | |||
134 | return NULL; | ||
135 | } | ||
136 | |||
88 | static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) | 137 | static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) |
89 | { | 138 | { |
90 | unsigned char buf; | 139 | unsigned char buf; |
@@ -138,20 +187,34 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i | |||
138 | return ret; | 187 | return ret; |
139 | } | 188 | } |
140 | 189 | ||
141 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | 190 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, |
191 | int protocol, | ||
192 | int source_id) | ||
142 | { | 193 | { |
143 | int err; | 194 | int err; |
144 | unsigned char data; | 195 | unsigned char data; |
145 | struct usb_device *dev = chip->dev; | 196 | struct usb_device *dev = chip->dev; |
146 | struct uac_clock_source_descriptor *cs_desc = | 197 | u32 bmControls; |
147 | snd_usb_find_clock_source(chip->ctrl_intf, source_id); | 198 | |
148 | 199 | if (protocol == UAC_VERSION_3) { | |
149 | if (!cs_desc) | 200 | struct uac3_clock_source_descriptor *cs_desc = |
150 | return 0; | 201 | snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); |
202 | |||
203 | if (!cs_desc) | ||
204 | return 0; | ||
205 | bmControls = le32_to_cpu(cs_desc->bmControls); | ||
206 | } else { /* UAC_VERSION_1/2 */ | ||
207 | struct uac_clock_source_descriptor *cs_desc = | ||
208 | snd_usb_find_clock_source(chip->ctrl_intf, source_id); | ||
209 | |||
210 | if (!cs_desc) | ||
211 | return 0; | ||
212 | bmControls = cs_desc->bmControls; | ||
213 | } | ||
151 | 214 | ||
152 | /* If a clock source can't tell us whether it's valid, we assume it is */ | 215 | /* If a clock source can't tell us whether it's valid, we assume it is */ |
153 | if (!uac2_control_is_readable(cs_desc->bmControls, | 216 | if (!uac_v2v3_control_is_readable(bmControls, |
154 | UAC2_CS_CONTROL_CLOCK_VALID - 1)) | 217 | UAC2_CS_CONTROL_CLOCK_VALID)) |
155 | return 1; | 218 | return 1; |
156 | 219 | ||
157 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | 220 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
@@ -170,9 +233,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | |||
170 | return !!data; | 233 | return !!data; |
171 | } | 234 | } |
172 | 235 | ||
173 | static int __uac_clock_find_source(struct snd_usb_audio *chip, | 236 | static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, |
174 | int entity_id, unsigned long *visited, | 237 | unsigned long *visited, bool validate) |
175 | bool validate) | ||
176 | { | 238 | { |
177 | struct uac_clock_source_descriptor *source; | 239 | struct uac_clock_source_descriptor *source; |
178 | struct uac_clock_selector_descriptor *selector; | 240 | struct uac_clock_selector_descriptor *selector; |
@@ -191,7 +253,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
191 | source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); | 253 | source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); |
192 | if (source) { | 254 | if (source) { |
193 | entity_id = source->bClockID; | 255 | entity_id = source->bClockID; |
194 | if (validate && !uac_clock_source_is_valid(chip, entity_id)) { | 256 | if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2, |
257 | entity_id)) { | ||
195 | usb_audio_err(chip, | 258 | usb_audio_err(chip, |
196 | "clock source %d is not valid, cannot use\n", | 259 | "clock source %d is not valid, cannot use\n", |
197 | entity_id); | 260 | entity_id); |
@@ -260,6 +323,97 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
260 | return -EINVAL; | 323 | return -EINVAL; |
261 | } | 324 | } |
262 | 325 | ||
326 | static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, | ||
327 | unsigned long *visited, bool validate) | ||
328 | { | ||
329 | struct uac3_clock_source_descriptor *source; | ||
330 | struct uac3_clock_selector_descriptor *selector; | ||
331 | struct uac3_clock_multiplier_descriptor *multiplier; | ||
332 | |||
333 | entity_id &= 0xff; | ||
334 | |||
335 | if (test_and_set_bit(entity_id, visited)) { | ||
336 | usb_audio_warn(chip, | ||
337 | "%s(): recursive clock topology detected, id %d.\n", | ||
338 | __func__, entity_id); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | |||
342 | /* first, see if the ID we're looking for is a clock source already */ | ||
343 | source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); | ||
344 | if (source) { | ||
345 | entity_id = source->bClockID; | ||
346 | if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3, | ||
347 | entity_id)) { | ||
348 | usb_audio_err(chip, | ||
349 | "clock source %d is not valid, cannot use\n", | ||
350 | entity_id); | ||
351 | return -ENXIO; | ||
352 | } | ||
353 | return entity_id; | ||
354 | } | ||
355 | |||
356 | selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); | ||
357 | if (selector) { | ||
358 | int ret, i, cur; | ||
359 | |||
360 | /* the entity ID we are looking for is a selector. | ||
361 | * find out what it currently selects */ | ||
362 | ret = uac_clock_selector_get_val(chip, selector->bClockID); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | |||
366 | /* Selector values are one-based */ | ||
367 | |||
368 | if (ret > selector->bNrInPins || ret < 1) { | ||
369 | usb_audio_err(chip, | ||
370 | "%s(): selector reported illegal value, id %d, ret %d\n", | ||
371 | __func__, selector->bClockID, ret); | ||
372 | |||
373 | return -EINVAL; | ||
374 | } | ||
375 | |||
376 | cur = ret; | ||
377 | ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1], | ||
378 | visited, validate); | ||
379 | if (!validate || ret > 0 || !chip->autoclock) | ||
380 | return ret; | ||
381 | |||
382 | /* The current clock source is invalid, try others. */ | ||
383 | for (i = 1; i <= selector->bNrInPins; i++) { | ||
384 | int err; | ||
385 | |||
386 | if (i == cur) | ||
387 | continue; | ||
388 | |||
389 | ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1], | ||
390 | visited, true); | ||
391 | if (ret < 0) | ||
392 | continue; | ||
393 | |||
394 | err = uac_clock_selector_set_val(chip, entity_id, i); | ||
395 | if (err < 0) | ||
396 | continue; | ||
397 | |||
398 | usb_audio_info(chip, | ||
399 | "found and selected valid clock source %d\n", | ||
400 | ret); | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | return -ENXIO; | ||
405 | } | ||
406 | |||
407 | /* FIXME: multipliers only act as pass-thru element for now */ | ||
408 | multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, | ||
409 | entity_id); | ||
410 | if (multiplier) | ||
411 | return __uac3_clock_find_source(chip, multiplier->bCSourceID, | ||
412 | visited, validate); | ||
413 | |||
414 | return -EINVAL; | ||
415 | } | ||
416 | |||
263 | /* | 417 | /* |
264 | * For all kinds of sample rate settings and other device queries, | 418 | * For all kinds of sample rate settings and other device queries, |
265 | * the clock source (end-leaf) must be used. However, clock selectors, | 419 | * the clock source (end-leaf) must be used. However, clock selectors, |
@@ -271,12 +425,22 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, | |||
271 | * | 425 | * |
272 | * Returns the clock source UnitID (>=0) on success, or an error. | 426 | * Returns the clock source UnitID (>=0) on success, or an error. |
273 | */ | 427 | */ |
274 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, | 428 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, |
275 | bool validate) | 429 | int entity_id, bool validate) |
276 | { | 430 | { |
277 | DECLARE_BITMAP(visited, 256); | 431 | DECLARE_BITMAP(visited, 256); |
278 | memset(visited, 0, sizeof(visited)); | 432 | memset(visited, 0, sizeof(visited)); |
279 | return __uac_clock_find_source(chip, entity_id, visited, validate); | 433 | |
434 | switch (protocol) { | ||
435 | case UAC_VERSION_2: | ||
436 | return __uac_clock_find_source(chip, entity_id, visited, | ||
437 | validate); | ||
438 | case UAC_VERSION_3: | ||
439 | return __uac3_clock_find_source(chip, entity_id, visited, | ||
440 | validate); | ||
441 | default: | ||
442 | return -EINVAL; | ||
443 | } | ||
280 | } | 444 | } |
281 | 445 | ||
282 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | 446 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, |
@@ -335,7 +499,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | |||
335 | return 0; | 499 | return 0; |
336 | } | 500 | } |
337 | 501 | ||
338 | static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, | 502 | static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, |
339 | int altsetting, int clock) | 503 | int altsetting, int clock) |
340 | { | 504 | { |
341 | struct usb_device *dev = chip->dev; | 505 | struct usb_device *dev = chip->dev; |
@@ -348,7 +512,7 @@ static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, | |||
348 | snd_usb_ctrl_intf(chip) | (clock << 8), | 512 | snd_usb_ctrl_intf(chip) | (clock << 8), |
349 | &data, sizeof(data)); | 513 | &data, sizeof(data)); |
350 | if (err < 0) { | 514 | if (err < 0) { |
351 | dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d\n", | 515 | dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", |
352 | iface, altsetting, err); | 516 | iface, altsetting, err); |
353 | return 0; | 517 | return 0; |
354 | } | 518 | } |
@@ -356,7 +520,7 @@ static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, | |||
356 | return le32_to_cpu(data); | 520 | return le32_to_cpu(data); |
357 | } | 521 | } |
358 | 522 | ||
359 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | 523 | static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, |
360 | struct usb_host_interface *alts, | 524 | struct usb_host_interface *alts, |
361 | struct audioformat *fmt, int rate) | 525 | struct audioformat *fmt, int rate) |
362 | { | 526 | { |
@@ -365,18 +529,31 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | |||
365 | int err, cur_rate, prev_rate; | 529 | int err, cur_rate, prev_rate; |
366 | int clock; | 530 | int clock; |
367 | bool writeable; | 531 | bool writeable; |
368 | struct uac_clock_source_descriptor *cs_desc; | 532 | u32 bmControls; |
369 | 533 | ||
370 | clock = snd_usb_clock_find_source(chip, fmt->clock, true); | 534 | clock = snd_usb_clock_find_source(chip, fmt->protocol, |
535 | fmt->clock, true); | ||
371 | if (clock < 0) | 536 | if (clock < 0) |
372 | return clock; | 537 | return clock; |
373 | 538 | ||
374 | prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); | 539 | prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); |
375 | if (prev_rate == rate) | 540 | if (prev_rate == rate) |
376 | return 0; | 541 | return 0; |
377 | 542 | ||
378 | cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); | 543 | if (fmt->protocol == UAC_VERSION_3) { |
379 | writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1); | 544 | struct uac3_clock_source_descriptor *cs_desc; |
545 | |||
546 | cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); | ||
547 | bmControls = le32_to_cpu(cs_desc->bmControls); | ||
548 | } else { | ||
549 | struct uac_clock_source_descriptor *cs_desc; | ||
550 | |||
551 | cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); | ||
552 | bmControls = cs_desc->bmControls; | ||
553 | } | ||
554 | |||
555 | writeable = uac_v2v3_control_is_writeable(bmControls, | ||
556 | UAC2_CS_CONTROL_SAM_FREQ); | ||
380 | if (writeable) { | 557 | if (writeable) { |
381 | data = cpu_to_le32(rate); | 558 | data = cpu_to_le32(rate); |
382 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | 559 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, |
@@ -386,12 +563,13 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | |||
386 | &data, sizeof(data)); | 563 | &data, sizeof(data)); |
387 | if (err < 0) { | 564 | if (err < 0) { |
388 | usb_audio_err(chip, | 565 | usb_audio_err(chip, |
389 | "%d:%d: cannot set freq %d (v2): err %d\n", | 566 | "%d:%d: cannot set freq %d (v2/v3): err %d\n", |
390 | iface, fmt->altsetting, rate, err); | 567 | iface, fmt->altsetting, rate, err); |
391 | return err; | 568 | return err; |
392 | } | 569 | } |
393 | 570 | ||
394 | cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); | 571 | cur_rate = get_sample_rate_v2v3(chip, iface, |
572 | fmt->altsetting, clock); | ||
395 | } else { | 573 | } else { |
396 | cur_rate = prev_rate; | 574 | cur_rate = prev_rate; |
397 | } | 575 | } |
@@ -430,7 +608,8 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |||
430 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | 608 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
431 | 609 | ||
432 | case UAC_VERSION_2: | 610 | case UAC_VERSION_2: |
433 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | 611 | case UAC_VERSION_3: |
612 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); | ||
434 | } | 613 | } |
435 | } | 614 | } |
436 | 615 | ||