Blame view
sound/usb/clock.c
11.3 KB
79f920fbf
|
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
|
22 23 |
#include <linux/string.h> #include <linux/usb.h> |
79f920fbf
|
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
|
30 31 32 |
#include "usbaudio.h" #include "card.h" |
79f920fbf
|
33 |
#include "helper.h" |
f22aa9490
|
34 |
#include "clock.h" |
21bb5aafc
|
35 |
#include "quirks.h" |
79f920fbf
|
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
|
93 94 |
UAC2_CX_CLOCK_SELECTOR << 8, snd_usb_ctrl_intf(chip) | (selector_id << 8), |
17d900c4a
|
95 |
&buf, sizeof(buf)); |
79f920fbf
|
96 97 98 99 100 101 |
if (ret < 0) return ret; return buf; } |
8c55af3f6
|
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
|
117 118 119 120 |
usb_audio_err(chip, "setting selector (id %d) unexpected length %d ", selector_id, ret); |
8c55af3f6
|
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
|
129 130 131 132 |
usb_audio_err(chip, "setting selector (id %d) to %x failed (current: %d) ", selector_id, pin, ret); |
8c55af3f6
|
133 134 135 136 137 |
return -EINVAL; } return ret; } |
79f920fbf
|
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
|
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
|
150 151 |
if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID - 1)) |
3bc6fbc74
|
152 |
return 1; |
79f920fbf
|
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
|
156 157 |
UAC2_CS_CONTROL_CLOCK_VALID << 8, snd_usb_ctrl_intf(chip) | (source_id << 8), |
17d900c4a
|
158 |
&data, sizeof(data)); |
79f920fbf
|
159 160 |
if (err < 0) { |
0ba41d917
|
161 162 163 |
dev_warn(&dev->dev, "%s(): cannot get clock validity for id %d ", |
79f920fbf
|
164 |
__func__, source_id); |
3bc6fbc74
|
165 |
return 0; |
79f920fbf
|
166 167 168 169 |
} return !!data; } |
79f920fbf
|
170 |
static int __uac_clock_find_source(struct snd_usb_audio *chip, |
06ffc1ebd
|
171 172 |
int entity_id, unsigned long *visited, bool validate) |
79f920fbf
|
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
|
181 182 183 184 |
usb_audio_warn(chip, "%s(): recursive clock topology detected, id %d. ", __func__, entity_id); |
79f920fbf
|
185 186 187 188 |
return -EINVAL; } /* first, see if the ID we're looking for is a clock source already */ |
3d8d4dcfd
|
189 |
source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); |
06ffc1ebd
|
190 191 192 |
if (source) { entity_id = source->bClockID; if (validate && !uac_clock_source_is_valid(chip, entity_id)) { |
0ba41d917
|
193 194 195 196 |
usb_audio_err(chip, "clock source %d is not valid, cannot use ", entity_id); |
06ffc1ebd
|
197 198 199 200 |
return -ENXIO; } return entity_id; } |
79f920fbf
|
201 |
|
3d8d4dcfd
|
202 |
selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); |
79f920fbf
|
203 |
if (selector) { |
8c55af3f6
|
204 |
int ret, i, cur; |
79f920fbf
|
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
|
211 |
/* Selector values are one-based */ |
79f920fbf
|
212 |
if (ret > selector->bNrInPins || ret < 1) { |
0ba41d917
|
213 |
usb_audio_err(chip, |
79f920fbf
|
214 215 216 217 218 219 |
"%s(): selector reported illegal value, id %d, ret %d ", __func__, selector->bClockID, ret); return -EINVAL; } |
8c55af3f6
|
220 221 |
cur = ret; ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], |
06ffc1ebd
|
222 |
visited, validate); |
ef02e29b0
|
223 |
if (!validate || ret > 0 || !chip->autoclock) |
8c55af3f6
|
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
|
241 242 243 244 |
usb_audio_info(chip, "found and selected valid clock source %d ", ret); |
8c55af3f6
|
245 246 247 248 |
return ret; } return -ENXIO; |
79f920fbf
|
249 250 251 |
} /* FIXME: multipliers only act as pass-thru element for now */ |
3d8d4dcfd
|
252 |
multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); |
79f920fbf
|
253 |
if (multiplier) |
3d8d4dcfd
|
254 |
return __uac_clock_find_source(chip, multiplier->bCSourceID, |
06ffc1ebd
|
255 |
visited, validate); |
79f920fbf
|
256 257 258 |
return -EINVAL; } |
157a57b6f
|
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
|
270 271 |
int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, bool validate) |
79f920fbf
|
272 273 274 |
{ DECLARE_BITMAP(visited, 256); memset(visited, 0, sizeof(visited)); |
06ffc1ebd
|
275 |
return __uac_clock_find_source(chip, entity_id, visited, validate); |
79f920fbf
|
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
|
290 |
if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) |
79f920fbf
|
291 |
return 0; |
79f920fbf
|
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
|
299 |
data, sizeof(data))) < 0) { |
0ba41d917
|
300 301 302 |
dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x ", iface, fmt->altsetting, rate, ep); |
79f920fbf
|
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
|
309 |
data, sizeof(data))) < 0) { |
0ba41d917
|
310 311 312 |
dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x ", iface, fmt->altsetting, ep); |
79f920fbf
|
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
|
318 319 |
dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d ", crate, rate); |
79f920fbf
|
320 321 322 323 324 |
// runtime->rate = crate; } return 0; } |
7c5174651
|
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
|
329 |
__le32 data; |
7c5174651
|
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
|
336 |
&data, sizeof(data)); |
7c5174651
|
337 |
if (err < 0) { |
0ba41d917
|
338 339 340 |
dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d ", iface, altsetting, err); |
7c5174651
|
341 342 |
return 0; } |
f6a8bc70f
|
343 |
return le32_to_cpu(data); |
7c5174651
|
344 |
} |
79f920fbf
|
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
|
350 |
__le32 data; |
690a863ff
|
351 |
int err, cur_rate, prev_rate; |
8c55af3f6
|
352 |
int clock; |
1dc669fed
|
353 354 |
bool writeable; struct uac_clock_source_descriptor *cs_desc; |
79f920fbf
|
355 |
|
8c55af3f6
|
356 |
clock = snd_usb_clock_find_source(chip, fmt->clock, true); |
79f920fbf
|
357 358 |
if (clock < 0) return clock; |
7c5174651
|
359 |
prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); |
fa92dd77e
|
360 361 |
if (prev_rate == rate) return 0; |
690a863ff
|
362 |
|
1dc669fed
|
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
|
373 374 375 376 |
usb_audio_err(chip, "%d:%d: cannot set freq %d (v2): err %d ", iface, fmt->altsetting, rate, err); |
1dc669fed
|
377 378 |
return err; } |
79f920fbf
|
379 |
|
1dc669fed
|
380 381 382 383 |
cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); } else { cur_rate = prev_rate; } |
79f920fbf
|
384 |
|
690a863ff
|
385 |
if (cur_rate != rate) { |
1dc669fed
|
386 |
if (!writeable) { |
0ba41d917
|
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
|
391 392 |
return -ENXIO; } |
0ba41d917
|
393 394 395 396 |
usb_audio_dbg(chip, "current rate %d is different from the runtime rate %d ", cur_rate, rate); |
690a863ff
|
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
|
403 |
snd_usb_set_interface_quirk(dev); |
690a863ff
|
404 |
usb_set_interface(dev, iface, fmt->altsetting); |
21bb5aafc
|
405 |
snd_usb_set_interface_quirk(dev); |
690a863ff
|
406 |
} |
79f920fbf
|
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
|
415 |
switch (fmt->protocol) { |
79f920fbf
|
416 |
case UAC_VERSION_1: |
a2acad829
|
417 |
default: |
79f920fbf
|
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
|
423 |
} |