Blame view

sound/usb/clock.c 11.3 KB
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *   Clock domain and sample rate management functions
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
  
  #include <linux/bitops.h>
  #include <linux/init.h>
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
22
23
  #include <linux/string.h>
  #include <linux/usb.h>
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
24
25
26
27
28
29
  #include <linux/usb/audio.h>
  #include <linux/usb/audio-v2.h>
  
  #include <sound/core.h>
  #include <sound/info.h>
  #include <sound/pcm.h>
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
30
31
32
  
  #include "usbaudio.h"
  #include "card.h"
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
33
  #include "helper.h"
f22aa9490   Daniel Mack   ALSA: usb-audio: ...
34
  #include "clock.h"
21bb5aafc   Daniel Mack   ALSA: snd-usb: Pl...
35
  #include "quirks.h"
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  
  static struct uac_clock_source_descriptor *
  	snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
  				  int clock_id)
  {
  	struct uac_clock_source_descriptor *cs = NULL;
  
  	while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
  					     ctrl_iface->extralen,
  					     cs, UAC2_CLOCK_SOURCE))) {
  		if (cs->bClockID == clock_id)
  			return cs;
  	}
  
  	return NULL;
  }
  
  static struct uac_clock_selector_descriptor *
  	snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
  				    int clock_id)
  {
  	struct uac_clock_selector_descriptor *cs = NULL;
  
  	while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
  					     ctrl_iface->extralen,
  					     cs, UAC2_CLOCK_SELECTOR))) {
  		if (cs->bClockID == clock_id)
  			return cs;
  	}
  
  	return NULL;
  }
  
  static struct uac_clock_multiplier_descriptor *
  	snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
  				      int clock_id)
  {
  	struct uac_clock_multiplier_descriptor *cs = NULL;
  
  	while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
  					     ctrl_iface->extralen,
  					     cs, UAC2_CLOCK_MULTIPLIER))) {
  		if (cs->bClockID == clock_id)
  			return cs;
  	}
  
  	return NULL;
  }
  
  static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
  {
  	unsigned char buf;
  	int ret;
  
  	ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
  			      UAC2_CS_CUR,
  			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
11bcbc443   Daniel Mack   ALSA: usb-audio: ...
93
94
  			      UAC2_CX_CLOCK_SELECTOR << 8,
  			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
95
  			      &buf, sizeof(buf));
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
96
97
98
99
100
101
  
  	if (ret < 0)
  		return ret;
  
  	return buf;
  }
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
  					unsigned char pin)
  {
  	int ret;
  
  	ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
  			      UAC2_CS_CUR,
  			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
  			      UAC2_CX_CLOCK_SELECTOR << 8,
  			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
  			      &pin, sizeof(pin));
  	if (ret < 0)
  		return ret;
  
  	if (ret != sizeof(pin)) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
117
118
119
120
  		usb_audio_err(chip,
  			"setting selector (id %d) unexpected length %d
  ",
  			selector_id, ret);
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
121
122
123
124
125
126
127
128
  		return -EINVAL;
  	}
  
  	ret = uac_clock_selector_get_val(chip, selector_id);
  	if (ret < 0)
  		return ret;
  
  	if (ret != pin) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
129
130
131
132
  		usb_audio_err(chip,
  			"setting selector (id %d) to %x failed (current: %d)
  ",
  			selector_id, pin, ret);
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
133
134
135
136
137
  		return -EINVAL;
  	}
  
  	return ret;
  }
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
138
139
140
141
142
  static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
  {
  	int err;
  	unsigned char data;
  	struct usb_device *dev = chip->dev;
3bc6fbc74   Daniel Mack   ALSA: usb-audio: ...
143
144
145
146
147
148
149
  	struct uac_clock_source_descriptor *cs_desc =
  		snd_usb_find_clock_source(chip->ctrl_intf, source_id);
  
  	if (!cs_desc)
  		return 0;
  
  	/* If a clock source can't tell us whether it's valid, we assume it is */
aff252a84   Daniel Mack   ALSA: snd-usb: fi...
150
151
  	if (!uac2_control_is_readable(cs_desc->bmControls,
  				      UAC2_CS_CONTROL_CLOCK_VALID - 1))
3bc6fbc74   Daniel Mack   ALSA: usb-audio: ...
152
  		return 1;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
153
154
155
  
  	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
  			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
11bcbc443   Daniel Mack   ALSA: usb-audio: ...
156
157
  			      UAC2_CS_CONTROL_CLOCK_VALID << 8,
  			      snd_usb_ctrl_intf(chip) | (source_id << 8),
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
158
  			      &data, sizeof(data));
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
159
160
  
  	if (err < 0) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
161
162
163
  		dev_warn(&dev->dev,
  			 "%s(): cannot get clock validity for id %d
  ",
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
164
  			   __func__, source_id);
3bc6fbc74   Daniel Mack   ALSA: usb-audio: ...
165
  		return 0;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
166
167
168
169
  	}
  
  	return !!data;
  }
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
170
  static int __uac_clock_find_source(struct snd_usb_audio *chip,
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
171
172
  				   int entity_id, unsigned long *visited,
  				   bool validate)
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
173
174
175
176
177
178
179
180
  {
  	struct uac_clock_source_descriptor *source;
  	struct uac_clock_selector_descriptor *selector;
  	struct uac_clock_multiplier_descriptor *multiplier;
  
  	entity_id &= 0xff;
  
  	if (test_and_set_bit(entity_id, visited)) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
181
182
183
184
  		usb_audio_warn(chip,
  			 "%s(): recursive clock topology detected, id %d.
  ",
  			 __func__, entity_id);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
185
186
187
188
  		return -EINVAL;
  	}
  
  	/* first, see if the ID we're looking for is a clock source already */
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
189
  	source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
190
191
192
  	if (source) {
  		entity_id = source->bClockID;
  		if (validate && !uac_clock_source_is_valid(chip, entity_id)) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
193
194
195
196
  			usb_audio_err(chip,
  				"clock source %d is not valid, cannot use
  ",
  				entity_id);
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
197
198
199
200
  			return -ENXIO;
  		}
  		return entity_id;
  	}
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
201

3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
202
  	selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
203
  	if (selector) {
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
204
  		int ret, i, cur;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
205
206
207
208
209
210
  
  		/* the entity ID we are looking for is a selector.
  		 * find out what it currently selects */
  		ret = uac_clock_selector_get_val(chip, selector->bClockID);
  		if (ret < 0)
  			return ret;
157a57b6f   Daniel Mack   ALSA: usb-audio: ...
211
  		/* Selector values are one-based */
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
212
  		if (ret > selector->bNrInPins || ret < 1) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
213
  			usb_audio_err(chip,
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
214
215
216
217
218
219
  				"%s(): selector reported illegal value, id %d, ret %d
  ",
  				__func__, selector->bClockID, ret);
  
  			return -EINVAL;
  		}
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
220
221
  		cur = ret;
  		ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
222
  					       visited, validate);
ef02e29b0   Eldad Zack   ALSA: usb-audio: ...
223
  		if (!validate || ret > 0 || !chip->autoclock)
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  			return ret;
  
  		/* The current clock source is invalid, try others. */
  		for (i = 1; i <= selector->bNrInPins; i++) {
  			int err;
  
  			if (i == cur)
  				continue;
  
  			ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
  				visited, true);
  			if (ret < 0)
  				continue;
  
  			err = uac_clock_selector_set_val(chip, entity_id, i);
  			if (err < 0)
  				continue;
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
241
242
243
244
  			usb_audio_info(chip,
  				 "found and selected valid clock source %d
  ",
  				 ret);
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
245
246
247
248
  			return ret;
  		}
  
  		return -ENXIO;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
249
250
251
  	}
  
  	/* FIXME: multipliers only act as pass-thru element for now */
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
252
  	multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
253
  	if (multiplier)
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
254
  		return __uac_clock_find_source(chip, multiplier->bCSourceID,
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
255
  						visited, validate);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
256
257
258
  
  	return -EINVAL;
  }
157a57b6f   Daniel Mack   ALSA: usb-audio: ...
259
260
261
262
263
264
265
266
267
268
269
  /*
   * For all kinds of sample rate settings and other device queries,
   * the clock source (end-leaf) must be used. However, clock selectors,
   * clock multipliers and sample rate converters may be specified as
   * clock source input to terminal. This functions walks the clock path
   * to its end and tries to find the source.
   *
   * The 'visited' bitfield is used internally to detect recursive loops.
   *
   * Returns the clock source UnitID (>=0) on success, or an error.
   */
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
270
271
  int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id,
  			      bool validate)
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
272
273
274
  {
  	DECLARE_BITMAP(visited, 256);
  	memset(visited, 0, sizeof(visited));
06ffc1ebd   Eldad Zack   ALSA: usb-audio: ...
275
  	return __uac_clock_find_source(chip, entity_id, visited, validate);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  }
  
  static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
  			      struct usb_host_interface *alts,
  			      struct audioformat *fmt, int rate)
  {
  	struct usb_device *dev = chip->dev;
  	unsigned int ep;
  	unsigned char data[3];
  	int err, crate;
  
  	ep = get_endpoint(alts, 0)->bEndpointAddress;
  
  	/* if endpoint doesn't have sampling rate control, bail out */
d32d552e6   Clemens Ladisch   ALSA: usb-audio: ...
290
  	if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
291
  		return 0;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
292
293
294
295
296
297
298
  
  	data[0] = rate;
  	data[1] = rate >> 8;
  	data[2] = rate >> 16;
  	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
  				   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
  				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
299
  				   data, sizeof(data))) < 0) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
300
301
302
  		dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x
  ",
  			iface, fmt->altsetting, rate, ep);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
303
304
305
306
307
308
  		return err;
  	}
  
  	if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
  				   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
  				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
309
  				   data, sizeof(data))) < 0) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
310
311
312
  		dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x
  ",
  			iface, fmt->altsetting, ep);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
313
314
315
316
317
  		return 0; /* some devices don't support reading */
  	}
  
  	crate = data[0] | (data[1] << 8) | (data[2] << 16);
  	if (crate != rate) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
318
319
  		dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d
  ", crate, rate);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
320
321
322
323
324
  		// runtime->rate = crate;
  	}
  
  	return 0;
  }
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
325
326
327
328
  static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface,
  			      int altsetting, int clock)
  {
  	struct usb_device *dev = chip->dev;
f6a8bc70f   Eldad Zack   ALSA: usb-audio: ...
329
  	__le32 data;
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
330
331
332
333
334
335
  	int err;
  
  	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
  			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
  			      UAC2_CS_CONTROL_SAM_FREQ << 8,
  			      snd_usb_ctrl_intf(chip) | (clock << 8),
f6a8bc70f   Eldad Zack   ALSA: usb-audio: ...
336
  			      &data, sizeof(data));
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
337
  	if (err < 0) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
338
339
340
  		dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d
  ",
  			 iface, altsetting, err);
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
341
342
  		return 0;
  	}
f6a8bc70f   Eldad Zack   ALSA: usb-audio: ...
343
  	return le32_to_cpu(data);
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
344
  }
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
345
346
347
348
349
  static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
  			      struct usb_host_interface *alts,
  			      struct audioformat *fmt, int rate)
  {
  	struct usb_device *dev = chip->dev;
f6a8bc70f   Eldad Zack   ALSA: usb-audio: ...
350
  	__le32 data;
690a863ff   Torstein Hegge   ALSA: usb: Work a...
351
  	int err, cur_rate, prev_rate;
8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
352
  	int clock;
1dc669fed   Eldad Zack   ALSA: usb-audio: ...
353
354
  	bool writeable;
  	struct uac_clock_source_descriptor *cs_desc;
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
355

8c55af3f6   Eldad Zack   ALSA: usb-audio: ...
356
  	clock = snd_usb_clock_find_source(chip, fmt->clock, true);
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
357
358
  	if (clock < 0)
  		return clock;
7c5174651   Takashi Iwai   ALSA: usb-audio: ...
359
  	prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
fa92dd77e   David Henningsson   ALSA: usb - Avoid...
360
361
  	if (prev_rate == rate)
  		return 0;
690a863ff   Torstein Hegge   ALSA: usb: Work a...
362

1dc669fed   Eldad Zack   ALSA: usb-audio: ...
363
364
365
366
367
368
369
370
371
372
  	cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
  	writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1);
  	if (writeable) {
  		data = cpu_to_le32(rate);
  		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
  				      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
  				      UAC2_CS_CONTROL_SAM_FREQ << 8,
  				      snd_usb_ctrl_intf(chip) | (clock << 8),
  				      &data, sizeof(data));
  		if (err < 0) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
373
374
375
376
  			usb_audio_err(chip,
  				"%d:%d: cannot set freq %d (v2): err %d
  ",
  				iface, fmt->altsetting, rate, err);
1dc669fed   Eldad Zack   ALSA: usb-audio: ...
377
378
  			return err;
  		}
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
379

1dc669fed   Eldad Zack   ALSA: usb-audio: ...
380
381
382
383
  		cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock);
  	} else {
  		cur_rate = prev_rate;
  	}
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
384

690a863ff   Torstein Hegge   ALSA: usb: Work a...
385
  	if (cur_rate != rate) {
1dc669fed   Eldad Zack   ALSA: usb-audio: ...
386
  		if (!writeable) {
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
387
388
389
390
  			usb_audio_warn(chip,
  				 "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d
  ",
  				 iface, fmt->altsetting, rate, cur_rate);
1dc669fed   Eldad Zack   ALSA: usb-audio: ...
391
392
  			return -ENXIO;
  		}
0ba41d917   Takashi Iwai   ALSA: usb-audio: ...
393
394
395
396
  		usb_audio_dbg(chip,
  			"current rate %d is different from the runtime rate %d
  ",
  			cur_rate, rate);
690a863ff   Torstein Hegge   ALSA: usb: Work a...
397
398
399
400
401
402
  	}
  
  	/* Some devices doesn't respond to sample rate changes while the
  	 * interface is active. */
  	if (rate != prev_rate) {
  		usb_set_interface(dev, iface, 0);
21bb5aafc   Daniel Mack   ALSA: snd-usb: Pl...
403
  		snd_usb_set_interface_quirk(dev);
690a863ff   Torstein Hegge   ALSA: usb: Work a...
404
  		usb_set_interface(dev, iface, fmt->altsetting);
21bb5aafc   Daniel Mack   ALSA: snd-usb: Pl...
405
  		snd_usb_set_interface_quirk(dev);
690a863ff   Torstein Hegge   ALSA: usb: Work a...
406
  	}
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
407
408
409
410
411
412
413
414
  
  	return 0;
  }
  
  int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
  			     struct usb_host_interface *alts,
  			     struct audioformat *fmt, int rate)
  {
8f898e92a   Clemens Ladisch   ALSA: usb-audio: ...
415
  	switch (fmt->protocol) {
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
416
  	case UAC_VERSION_1:
a2acad829   Clemens Ladisch   ALSA: usb-audio: ...
417
  	default:
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
418
419
420
421
422
  		return set_sample_rate_v1(chip, iface, alts, fmt, rate);
  
  	case UAC_VERSION_2:
  		return set_sample_rate_v2(chip, iface, alts, fmt, rate);
  	}
79f920fbf   Daniel Mack   ALSA: usb-audio: ...
423
  }