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