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