]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
79f920fb DM |
2 | /* |
3 | * Clock domain and sample rate management functions | |
79f920fb DM |
4 | */ |
5 | ||
6 | #include <linux/bitops.h> | |
7 | #include <linux/init.h> | |
79f920fb DM |
8 | #include <linux/string.h> |
9 | #include <linux/usb.h> | |
79f920fb DM |
10 | #include <linux/usb/audio.h> |
11 | #include <linux/usb/audio-v2.h> | |
9a2fe9b8 | 12 | #include <linux/usb/audio-v3.h> |
79f920fb DM |
13 | |
14 | #include <sound/core.h> | |
15 | #include <sound/info.h> | |
16 | #include <sound/pcm.h> | |
79f920fb DM |
17 | |
18 | #include "usbaudio.h" | |
19 | #include "card.h" | |
79f920fb | 20 | #include "helper.h" |
f22aa949 | 21 | #include "clock.h" |
21bb5aaf | 22 | #include "quirks.h" |
79f920fb | 23 | |
f7645bd6 TI |
24 | static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, |
25 | bool (*validator)(void *, int), u8 type) | |
79f920fb | 26 | { |
f7645bd6 | 27 | void *cs = NULL; |
79f920fb | 28 | |
f7645bd6 TI |
29 | while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, |
30 | cs, type))) { | |
31 | if (validator(cs, id)) | |
79f920fb DM |
32 | return cs; |
33 | } | |
34 | ||
35 | return NULL; | |
36 | } | |
37 | ||
f7645bd6 | 38 | static bool validate_clock_source_v2(void *p, int id) |
9a2fe9b8 | 39 | { |
f7645bd6 | 40 | struct uac_clock_source_descriptor *cs = p; |
b8e4f1fd | 41 | return cs->bClockID == id; |
9a2fe9b8 RB |
42 | } |
43 | ||
f7645bd6 | 44 | static bool validate_clock_source_v3(void *p, int id) |
79f920fb | 45 | { |
f7645bd6 | 46 | struct uac3_clock_source_descriptor *cs = p; |
b8e4f1fd | 47 | return cs->bClockID == id; |
79f920fb DM |
48 | } |
49 | ||
f7645bd6 | 50 | static bool validate_clock_selector_v2(void *p, int id) |
9a2fe9b8 | 51 | { |
f7645bd6 | 52 | struct uac_clock_selector_descriptor *cs = p; |
b8e4f1fd | 53 | return cs->bClockID == id; |
9a2fe9b8 RB |
54 | } |
55 | ||
f7645bd6 | 56 | static bool validate_clock_selector_v3(void *p, int id) |
79f920fb | 57 | { |
f7645bd6 | 58 | struct uac3_clock_selector_descriptor *cs = p; |
b8e4f1fd | 59 | return cs->bClockID == id; |
79f920fb DM |
60 | } |
61 | ||
f7645bd6 | 62 | static bool validate_clock_multiplier_v2(void *p, int id) |
9a2fe9b8 | 63 | { |
f7645bd6 | 64 | struct uac_clock_multiplier_descriptor *cs = p; |
b8e4f1fd | 65 | return cs->bClockID == id; |
f7645bd6 | 66 | } |
9a2fe9b8 | 67 | |
f7645bd6 TI |
68 | static bool validate_clock_multiplier_v3(void *p, int id) |
69 | { | |
70 | struct uac3_clock_multiplier_descriptor *cs = p; | |
b8e4f1fd | 71 | return cs->bClockID == id; |
f7645bd6 | 72 | } |
9a2fe9b8 | 73 | |
f7645bd6 TI |
74 | #define DEFINE_FIND_HELPER(name, obj, validator, type) \ |
75 | static obj *name(struct usb_host_interface *iface, int id) \ | |
76 | { \ | |
77 | return find_uac_clock_desc(iface, id, validator, type); \ | |
9a2fe9b8 RB |
78 | } |
79 | ||
f7645bd6 TI |
80 | DEFINE_FIND_HELPER(snd_usb_find_clock_source, |
81 | struct uac_clock_source_descriptor, | |
82 | validate_clock_source_v2, UAC2_CLOCK_SOURCE); | |
83 | DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3, | |
84 | struct uac3_clock_source_descriptor, | |
85 | validate_clock_source_v3, UAC3_CLOCK_SOURCE); | |
86 | ||
87 | DEFINE_FIND_HELPER(snd_usb_find_clock_selector, | |
88 | struct uac_clock_selector_descriptor, | |
89 | validate_clock_selector_v2, UAC2_CLOCK_SELECTOR); | |
90 | DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3, | |
91 | struct uac3_clock_selector_descriptor, | |
92 | validate_clock_selector_v3, UAC3_CLOCK_SELECTOR); | |
93 | ||
94 | DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, | |
95 | struct uac_clock_multiplier_descriptor, | |
96 | validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER); | |
97 | DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3, | |
98 | struct uac3_clock_multiplier_descriptor, | |
99 | validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER); | |
100 | ||
79f920fb DM |
101 | static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) |
102 | { | |
103 | unsigned char buf; | |
104 | int ret; | |
105 | ||
106 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), | |
107 | UAC2_CS_CUR, | |
108 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | |
11bcbc44 DM |
109 | UAC2_CX_CLOCK_SELECTOR << 8, |
110 | snd_usb_ctrl_intf(chip) | (selector_id << 8), | |
17d900c4 | 111 | &buf, sizeof(buf)); |
79f920fb DM |
112 | |
113 | if (ret < 0) | |
114 | return ret; | |
115 | ||
116 | return buf; | |
117 | } | |
118 | ||
8c55af3f EZ |
119 | static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, |
120 | unsigned char pin) | |
121 | { | |
122 | int ret; | |
123 | ||
124 | ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), | |
125 | UAC2_CS_CUR, | |
126 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | |
127 | UAC2_CX_CLOCK_SELECTOR << 8, | |
128 | snd_usb_ctrl_intf(chip) | (selector_id << 8), | |
129 | &pin, sizeof(pin)); | |
130 | if (ret < 0) | |
131 | return ret; | |
132 | ||
133 | if (ret != sizeof(pin)) { | |
0ba41d91 TI |
134 | usb_audio_err(chip, |
135 | "setting selector (id %d) unexpected length %d\n", | |
136 | selector_id, ret); | |
8c55af3f EZ |
137 | return -EINVAL; |
138 | } | |
139 | ||
140 | ret = uac_clock_selector_get_val(chip, selector_id); | |
141 | if (ret < 0) | |
142 | return ret; | |
143 | ||
144 | if (ret != pin) { | |
0ba41d91 TI |
145 | usb_audio_err(chip, |
146 | "setting selector (id %d) to %x failed (current: %d)\n", | |
147 | selector_id, pin, ret); | |
8c55af3f EZ |
148 | return -EINVAL; |
149 | } | |
150 | ||
151 | return ret; | |
152 | } | |
153 | ||
9f35a312 AT |
154 | static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, |
155 | struct audioformat *fmt, | |
156 | int source_id) | |
157 | { | |
2edb84e3 AT |
158 | bool ret = false; |
159 | int count; | |
160 | unsigned char data; | |
161 | struct usb_device *dev = chip->dev; | |
162 | ||
9f35a312 AT |
163 | if (fmt->protocol == UAC_VERSION_2) { |
164 | struct uac_clock_source_descriptor *cs_desc = | |
165 | snd_usb_find_clock_source(chip->ctrl_intf, source_id); | |
166 | ||
167 | if (!cs_desc) | |
168 | return false; | |
169 | ||
2edb84e3 AT |
170 | /* |
171 | * Assume the clock is valid if clock source supports only one | |
172 | * single sample rate, the terminal is connected directly to it | |
173 | * (there is no clock selector) and clock type is internal. | |
174 | * This is to deal with some Denon DJ controllers that always | |
175 | * reports that clock is invalid. | |
176 | */ | |
177 | if (fmt->nr_rates == 1 && | |
178 | (fmt->clock & 0xff) == cs_desc->bClockID && | |
179 | (cs_desc->bmAttributes & 0x3) != | |
180 | UAC_CLOCK_SOURCE_TYPE_EXT) | |
181 | return true; | |
182 | } | |
183 | ||
184 | /* | |
185 | * MOTU MicroBook IIc | |
186 | * Sample rate changes takes more than 2 seconds for this device. Clock | |
187 | * validity request returns false during that period. | |
188 | */ | |
189 | if (chip->usb_id == USB_ID(0x07fd, 0x0004)) { | |
190 | count = 0; | |
191 | ||
192 | while ((!ret) && (count < 50)) { | |
193 | int err; | |
194 | ||
195 | msleep(100); | |
196 | ||
197 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
198 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
199 | UAC2_CS_CONTROL_CLOCK_VALID << 8, | |
200 | snd_usb_ctrl_intf(chip) | (source_id << 8), | |
201 | &data, sizeof(data)); | |
202 | if (err < 0) { | |
203 | dev_warn(&dev->dev, | |
204 | "%s(): cannot get clock validity for id %d\n", | |
205 | __func__, source_id); | |
206 | return false; | |
207 | } | |
208 | ||
209 | ret = !!data; | |
210 | count++; | |
211 | } | |
9f35a312 AT |
212 | } |
213 | ||
2edb84e3 | 214 | return ret; |
9f35a312 AT |
215 | } |
216 | ||
9a2fe9b8 | 217 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, |
9f35a312 | 218 | struct audioformat *fmt, |
9a2fe9b8 | 219 | int source_id) |
79f920fb DM |
220 | { |
221 | int err; | |
222 | unsigned char data; | |
223 | struct usb_device *dev = chip->dev; | |
9a2fe9b8 RB |
224 | u32 bmControls; |
225 | ||
9f35a312 | 226 | if (fmt->protocol == UAC_VERSION_3) { |
9a2fe9b8 RB |
227 | struct uac3_clock_source_descriptor *cs_desc = |
228 | snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); | |
229 | ||
230 | if (!cs_desc) | |
1d4961d9 | 231 | return false; |
9a2fe9b8 RB |
232 | bmControls = le32_to_cpu(cs_desc->bmControls); |
233 | } else { /* UAC_VERSION_1/2 */ | |
234 | struct uac_clock_source_descriptor *cs_desc = | |
235 | snd_usb_find_clock_source(chip->ctrl_intf, source_id); | |
236 | ||
237 | if (!cs_desc) | |
1d4961d9 | 238 | return false; |
9a2fe9b8 RB |
239 | bmControls = cs_desc->bmControls; |
240 | } | |
3bc6fbc7 DM |
241 | |
242 | /* If a clock source can't tell us whether it's valid, we assume it is */ | |
9a2fe9b8 | 243 | if (!uac_v2v3_control_is_readable(bmControls, |
21e9b3e9 | 244 | UAC2_CS_CONTROL_CLOCK_VALID)) |
1d4961d9 | 245 | return true; |
79f920fb DM |
246 | |
247 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
248 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
11bcbc44 DM |
249 | UAC2_CS_CONTROL_CLOCK_VALID << 8, |
250 | snd_usb_ctrl_intf(chip) | (source_id << 8), | |
17d900c4 | 251 | &data, sizeof(data)); |
79f920fb DM |
252 | |
253 | if (err < 0) { | |
0ba41d91 TI |
254 | dev_warn(&dev->dev, |
255 | "%s(): cannot get clock validity for id %d\n", | |
79f920fb | 256 | __func__, source_id); |
1d4961d9 | 257 | return false; |
79f920fb DM |
258 | } |
259 | ||
9f35a312 AT |
260 | if (data) |
261 | return true; | |
262 | else | |
263 | return uac_clock_source_is_valid_quirk(chip, fmt, source_id); | |
79f920fb DM |
264 | } |
265 | ||
9f35a312 AT |
266 | static int __uac_clock_find_source(struct snd_usb_audio *chip, |
267 | struct audioformat *fmt, int entity_id, | |
9a2fe9b8 | 268 | unsigned long *visited, bool validate) |
79f920fb DM |
269 | { |
270 | struct uac_clock_source_descriptor *source; | |
271 | struct uac_clock_selector_descriptor *selector; | |
272 | struct uac_clock_multiplier_descriptor *multiplier; | |
273 | ||
274 | entity_id &= 0xff; | |
275 | ||
276 | if (test_and_set_bit(entity_id, visited)) { | |
0ba41d91 TI |
277 | usb_audio_warn(chip, |
278 | "%s(): recursive clock topology detected, id %d.\n", | |
279 | __func__, entity_id); | |
79f920fb DM |
280 | return -EINVAL; |
281 | } | |
282 | ||
283 | /* first, see if the ID we're looking for is a clock source already */ | |
3d8d4dcf | 284 | source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); |
06ffc1eb EZ |
285 | if (source) { |
286 | entity_id = source->bClockID; | |
9f35a312 | 287 | if (validate && !uac_clock_source_is_valid(chip, fmt, |
9a2fe9b8 | 288 | entity_id)) { |
0ba41d91 TI |
289 | usb_audio_err(chip, |
290 | "clock source %d is not valid, cannot use\n", | |
291 | entity_id); | |
06ffc1eb EZ |
292 | return -ENXIO; |
293 | } | |
294 | return entity_id; | |
295 | } | |
79f920fb | 296 | |
3d8d4dcf | 297 | selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); |
79f920fb | 298 | if (selector) { |
8c55af3f | 299 | int ret, i, cur; |
79f920fb DM |
300 | |
301 | /* the entity ID we are looking for is a selector. | |
302 | * find out what it currently selects */ | |
303 | ret = uac_clock_selector_get_val(chip, selector->bClockID); | |
304 | if (ret < 0) | |
305 | return ret; | |
306 | ||
157a57b6 DM |
307 | /* Selector values are one-based */ |
308 | ||
79f920fb | 309 | if (ret > selector->bNrInPins || ret < 1) { |
0ba41d91 | 310 | usb_audio_err(chip, |
79f920fb DM |
311 | "%s(): selector reported illegal value, id %d, ret %d\n", |
312 | __func__, selector->bClockID, ret); | |
313 | ||
314 | return -EINVAL; | |
315 | } | |
316 | ||
8c55af3f | 317 | cur = ret; |
9f35a312 AT |
318 | ret = __uac_clock_find_source(chip, fmt, |
319 | selector->baCSourceID[ret - 1], | |
320 | visited, validate); | |
ef02e29b | 321 | if (!validate || ret > 0 || !chip->autoclock) |
8c55af3f EZ |
322 | return ret; |
323 | ||
324 | /* The current clock source is invalid, try others. */ | |
325 | for (i = 1; i <= selector->bNrInPins; i++) { | |
326 | int err; | |
327 | ||
328 | if (i == cur) | |
329 | continue; | |
330 | ||
9f35a312 AT |
331 | ret = __uac_clock_find_source(chip, fmt, |
332 | selector->baCSourceID[i - 1], | |
333 | visited, true); | |
8c55af3f EZ |
334 | if (ret < 0) |
335 | continue; | |
336 | ||
337 | err = uac_clock_selector_set_val(chip, entity_id, i); | |
338 | if (err < 0) | |
339 | continue; | |
340 | ||
0ba41d91 TI |
341 | usb_audio_info(chip, |
342 | "found and selected valid clock source %d\n", | |
343 | ret); | |
8c55af3f EZ |
344 | return ret; |
345 | } | |
346 | ||
347 | return -ENXIO; | |
79f920fb DM |
348 | } |
349 | ||
350 | /* FIXME: multipliers only act as pass-thru element for now */ | |
3d8d4dcf | 351 | multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); |
79f920fb | 352 | if (multiplier) |
9f35a312 AT |
353 | return __uac_clock_find_source(chip, fmt, |
354 | multiplier->bCSourceID, | |
355 | visited, validate); | |
79f920fb DM |
356 | |
357 | return -EINVAL; | |
358 | } | |
359 | ||
9f35a312 AT |
360 | static int __uac3_clock_find_source(struct snd_usb_audio *chip, |
361 | struct audioformat *fmt, int entity_id, | |
362 | unsigned long *visited, bool validate) | |
9a2fe9b8 RB |
363 | { |
364 | struct uac3_clock_source_descriptor *source; | |
365 | struct uac3_clock_selector_descriptor *selector; | |
366 | struct uac3_clock_multiplier_descriptor *multiplier; | |
367 | ||
368 | entity_id &= 0xff; | |
369 | ||
370 | if (test_and_set_bit(entity_id, visited)) { | |
371 | usb_audio_warn(chip, | |
372 | "%s(): recursive clock topology detected, id %d.\n", | |
373 | __func__, entity_id); | |
374 | return -EINVAL; | |
375 | } | |
376 | ||
377 | /* first, see if the ID we're looking for is a clock source already */ | |
378 | source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); | |
379 | if (source) { | |
380 | entity_id = source->bClockID; | |
9f35a312 | 381 | if (validate && !uac_clock_source_is_valid(chip, fmt, |
9a2fe9b8 RB |
382 | entity_id)) { |
383 | usb_audio_err(chip, | |
384 | "clock source %d is not valid, cannot use\n", | |
385 | entity_id); | |
386 | return -ENXIO; | |
387 | } | |
388 | return entity_id; | |
389 | } | |
390 | ||
391 | selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); | |
392 | if (selector) { | |
393 | int ret, i, cur; | |
394 | ||
395 | /* the entity ID we are looking for is a selector. | |
396 | * find out what it currently selects */ | |
397 | ret = uac_clock_selector_get_val(chip, selector->bClockID); | |
398 | if (ret < 0) | |
399 | return ret; | |
400 | ||
401 | /* Selector values are one-based */ | |
402 | ||
403 | if (ret > selector->bNrInPins || ret < 1) { | |
404 | usb_audio_err(chip, | |
405 | "%s(): selector reported illegal value, id %d, ret %d\n", | |
406 | __func__, selector->bClockID, ret); | |
407 | ||
408 | return -EINVAL; | |
409 | } | |
410 | ||
411 | cur = ret; | |
9f35a312 AT |
412 | ret = __uac3_clock_find_source(chip, fmt, |
413 | selector->baCSourceID[ret - 1], | |
9a2fe9b8 RB |
414 | visited, validate); |
415 | if (!validate || ret > 0 || !chip->autoclock) | |
416 | return ret; | |
417 | ||
418 | /* The current clock source is invalid, try others. */ | |
419 | for (i = 1; i <= selector->bNrInPins; i++) { | |
420 | int err; | |
421 | ||
422 | if (i == cur) | |
423 | continue; | |
424 | ||
9f35a312 AT |
425 | ret = __uac3_clock_find_source(chip, fmt, |
426 | selector->baCSourceID[i - 1], | |
427 | visited, true); | |
9a2fe9b8 RB |
428 | if (ret < 0) |
429 | continue; | |
430 | ||
431 | err = uac_clock_selector_set_val(chip, entity_id, i); | |
432 | if (err < 0) | |
433 | continue; | |
434 | ||
435 | usb_audio_info(chip, | |
436 | "found and selected valid clock source %d\n", | |
437 | ret); | |
438 | return ret; | |
439 | } | |
440 | ||
441 | return -ENXIO; | |
442 | } | |
443 | ||
444 | /* FIXME: multipliers only act as pass-thru element for now */ | |
445 | multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, | |
446 | entity_id); | |
447 | if (multiplier) | |
9f35a312 AT |
448 | return __uac3_clock_find_source(chip, fmt, |
449 | multiplier->bCSourceID, | |
9a2fe9b8 RB |
450 | visited, validate); |
451 | ||
452 | return -EINVAL; | |
453 | } | |
454 | ||
157a57b6 DM |
455 | /* |
456 | * For all kinds of sample rate settings and other device queries, | |
457 | * the clock source (end-leaf) must be used. However, clock selectors, | |
458 | * clock multipliers and sample rate converters may be specified as | |
459 | * clock source input to terminal. This functions walks the clock path | |
460 | * to its end and tries to find the source. | |
461 | * | |
462 | * The 'visited' bitfield is used internally to detect recursive loops. | |
463 | * | |
464 | * Returns the clock source UnitID (>=0) on success, or an error. | |
465 | */ | |
9f35a312 AT |
466 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, |
467 | struct audioformat *fmt, bool validate) | |
79f920fb DM |
468 | { |
469 | DECLARE_BITMAP(visited, 256); | |
470 | memset(visited, 0, sizeof(visited)); | |
9a2fe9b8 | 471 | |
9f35a312 | 472 | switch (fmt->protocol) { |
9a2fe9b8 | 473 | case UAC_VERSION_2: |
9f35a312 | 474 | return __uac_clock_find_source(chip, fmt, fmt->clock, visited, |
9a2fe9b8 RB |
475 | validate); |
476 | case UAC_VERSION_3: | |
9f35a312 | 477 | return __uac3_clock_find_source(chip, fmt, fmt->clock, visited, |
9a2fe9b8 RB |
478 | validate); |
479 | default: | |
480 | return -EINVAL; | |
481 | } | |
79f920fb DM |
482 | } |
483 | ||
484 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | |
485 | struct usb_host_interface *alts, | |
486 | struct audioformat *fmt, int rate) | |
487 | { | |
488 | struct usb_device *dev = chip->dev; | |
489 | unsigned int ep; | |
490 | unsigned char data[3]; | |
491 | int err, crate; | |
492 | ||
447d6275 TI |
493 | if (get_iface_desc(alts)->bNumEndpoints < 1) |
494 | return -EINVAL; | |
79f920fb DM |
495 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
496 | ||
497 | /* if endpoint doesn't have sampling rate control, bail out */ | |
d32d552e | 498 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) |
79f920fb | 499 | return 0; |
79f920fb DM |
500 | |
501 | data[0] = rate; | |
502 | data[1] = rate >> 8; | |
503 | data[2] = rate >> 16; | |
f25ecf8f TI |
504 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
505 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, | |
506 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | |
507 | data, sizeof(data)); | |
508 | if (err < 0) { | |
0ba41d91 TI |
509 | dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", |
510 | iface, fmt->altsetting, rate, ep); | |
79f920fb DM |
511 | return err; |
512 | } | |
513 | ||
b62b9980 JT |
514 | /* Don't check the sample rate for devices which we know don't |
515 | * support reading */ | |
516 | if (snd_usb_get_sample_rate_quirk(chip)) | |
517 | return 0; | |
57dd5414 TI |
518 | /* the firmware is likely buggy, don't repeat to fail too many times */ |
519 | if (chip->sample_rate_read_error > 2) | |
520 | return 0; | |
b62b9980 | 521 | |
f25ecf8f TI |
522 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
523 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, | |
524 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | |
525 | data, sizeof(data)); | |
526 | if (err < 0) { | |
0ba41d91 TI |
527 | dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", |
528 | iface, fmt->altsetting, ep); | |
57dd5414 | 529 | chip->sample_rate_read_error++; |
79f920fb DM |
530 | return 0; /* some devices don't support reading */ |
531 | } | |
532 | ||
533 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | |
534 | if (crate != rate) { | |
0ba41d91 | 535 | dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate); |
79f920fb DM |
536 | // runtime->rate = crate; |
537 | } | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
9a2fe9b8 | 542 | static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, |
7c517465 TI |
543 | int altsetting, int clock) |
544 | { | |
545 | struct usb_device *dev = chip->dev; | |
f6a8bc70 | 546 | __le32 data; |
7c517465 TI |
547 | int err; |
548 | ||
549 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | |
550 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | |
551 | UAC2_CS_CONTROL_SAM_FREQ << 8, | |
552 | snd_usb_ctrl_intf(chip) | (clock << 8), | |
f6a8bc70 | 553 | &data, sizeof(data)); |
7c517465 | 554 | if (err < 0) { |
9a2fe9b8 | 555 | dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", |
0ba41d91 | 556 | iface, altsetting, err); |
7c517465 TI |
557 | return 0; |
558 | } | |
559 | ||
f6a8bc70 | 560 | return le32_to_cpu(data); |
7c517465 TI |
561 | } |
562 | ||
9a2fe9b8 | 563 | static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, |
79f920fb DM |
564 | struct usb_host_interface *alts, |
565 | struct audioformat *fmt, int rate) | |
566 | { | |
567 | struct usb_device *dev = chip->dev; | |
f6a8bc70 | 568 | __le32 data; |
690a863f | 569 | int err, cur_rate, prev_rate; |
8c55af3f | 570 | int clock; |
1dc669fe | 571 | bool writeable; |
9a2fe9b8 | 572 | u32 bmControls; |
79f920fb | 573 | |
58cabe87 AG |
574 | /* First, try to find a valid clock. This may trigger |
575 | * automatic clock selection if the current clock is not | |
576 | * valid. | |
577 | */ | |
9f35a312 | 578 | clock = snd_usb_clock_find_source(chip, fmt, true); |
58cabe87 AG |
579 | if (clock < 0) { |
580 | /* We did not find a valid clock, but that might be | |
581 | * because the current sample rate does not match an | |
582 | * external clock source. Try again without validation | |
583 | * and we will do another validation after setting the | |
584 | * rate. | |
585 | */ | |
9f35a312 | 586 | clock = snd_usb_clock_find_source(chip, fmt, false); |
58cabe87 AG |
587 | if (clock < 0) |
588 | return clock; | |
589 | } | |
79f920fb | 590 | |
9a2fe9b8 | 591 | prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); |
fa92dd77 | 592 | if (prev_rate == rate) |
58cabe87 | 593 | goto validation; |
690a863f | 594 | |
9a2fe9b8 RB |
595 | if (fmt->protocol == UAC_VERSION_3) { |
596 | struct uac3_clock_source_descriptor *cs_desc; | |
597 | ||
598 | cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); | |
599 | bmControls = le32_to_cpu(cs_desc->bmControls); | |
600 | } else { | |
601 | struct uac_clock_source_descriptor *cs_desc; | |
602 | ||
603 | cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); | |
604 | bmControls = cs_desc->bmControls; | |
605 | } | |
606 | ||
21e9b3e9 AC |
607 | writeable = uac_v2v3_control_is_writeable(bmControls, |
608 | UAC2_CS_CONTROL_SAM_FREQ); | |
1dc669fe EZ |
609 | if (writeable) { |
610 | data = cpu_to_le32(rate); | |
611 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | |
612 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | |
613 | UAC2_CS_CONTROL_SAM_FREQ << 8, | |
614 | snd_usb_ctrl_intf(chip) | (clock << 8), | |
615 | &data, sizeof(data)); | |
616 | if (err < 0) { | |
0ba41d91 | 617 | usb_audio_err(chip, |
9a2fe9b8 | 618 | "%d:%d: cannot set freq %d (v2/v3): err %d\n", |
0ba41d91 | 619 | iface, fmt->altsetting, rate, err); |
1dc669fe EZ |
620 | return err; |
621 | } | |
79f920fb | 622 | |
9a2fe9b8 RB |
623 | cur_rate = get_sample_rate_v2v3(chip, iface, |
624 | fmt->altsetting, clock); | |
1dc669fe EZ |
625 | } else { |
626 | cur_rate = prev_rate; | |
627 | } | |
79f920fb | 628 | |
690a863f | 629 | if (cur_rate != rate) { |
1dc669fe | 630 | if (!writeable) { |
0ba41d91 TI |
631 | usb_audio_warn(chip, |
632 | "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", | |
633 | iface, fmt->altsetting, rate, cur_rate); | |
1dc669fe EZ |
634 | return -ENXIO; |
635 | } | |
0ba41d91 TI |
636 | usb_audio_dbg(chip, |
637 | "current rate %d is different from the runtime rate %d\n", | |
638 | cur_rate, rate); | |
690a863f TH |
639 | } |
640 | ||
641 | /* Some devices doesn't respond to sample rate changes while the | |
642 | * interface is active. */ | |
643 | if (rate != prev_rate) { | |
644 | usb_set_interface(dev, iface, 0); | |
21bb5aaf | 645 | snd_usb_set_interface_quirk(dev); |
690a863f | 646 | usb_set_interface(dev, iface, fmt->altsetting); |
21bb5aaf | 647 | snd_usb_set_interface_quirk(dev); |
690a863f | 648 | } |
79f920fb | 649 | |
58cabe87 AG |
650 | validation: |
651 | /* validate clock after rate change */ | |
9f35a312 | 652 | if (!uac_clock_source_is_valid(chip, fmt, clock)) |
58cabe87 | 653 | return -ENXIO; |
79f920fb DM |
654 | return 0; |
655 | } | |
656 | ||
657 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |
658 | struct usb_host_interface *alts, | |
659 | struct audioformat *fmt, int rate) | |
660 | { | |
8f898e92 | 661 | switch (fmt->protocol) { |
79f920fb | 662 | case UAC_VERSION_1: |
a2acad82 | 663 | default: |
79f920fb DM |
664 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
665 | ||
9a2fe9b8 | 666 | case UAC_VERSION_3: |
17156f23 RB |
667 | if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { |
668 | if (rate != UAC3_BADD_SAMPLING_RATE) | |
669 | return -ENXIO; | |
670 | else | |
671 | return 0; | |
672 | } | |
673 | /* fall through */ | |
674 | case UAC_VERSION_2: | |
9a2fe9b8 | 675 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); |
79f920fb | 676 | } |
79f920fb DM |
677 | } |
678 |