11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 279f920fbSDaniel Mack /* 379f920fbSDaniel Mack * Clock domain and sample rate management functions 479f920fbSDaniel Mack */ 579f920fbSDaniel Mack 679f920fbSDaniel Mack #include <linux/bitops.h> 779f920fbSDaniel Mack #include <linux/init.h> 879f920fbSDaniel Mack #include <linux/string.h> 979f920fbSDaniel Mack #include <linux/usb.h> 1079f920fbSDaniel Mack #include <linux/usb/audio.h> 1179f920fbSDaniel Mack #include <linux/usb/audio-v2.h> 129a2fe9b8SRuslan Bilovol #include <linux/usb/audio-v3.h> 1379f920fbSDaniel Mack 1479f920fbSDaniel Mack #include <sound/core.h> 1579f920fbSDaniel Mack #include <sound/info.h> 1679f920fbSDaniel Mack #include <sound/pcm.h> 1779f920fbSDaniel Mack 1879f920fbSDaniel Mack #include "usbaudio.h" 1979f920fbSDaniel Mack #include "card.h" 2079f920fbSDaniel Mack #include "helper.h" 21f22aa949SDaniel Mack #include "clock.h" 2221bb5aafSDaniel Mack #include "quirks.h" 2379f920fbSDaniel Mack 24f7645bd6STakashi Iwai static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, 25f7645bd6STakashi Iwai bool (*validator)(void *, int), u8 type) 2679f920fbSDaniel Mack { 27f7645bd6STakashi Iwai void *cs = NULL; 2879f920fbSDaniel Mack 29f7645bd6STakashi Iwai while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, 30f7645bd6STakashi Iwai cs, type))) { 31f7645bd6STakashi Iwai if (validator(cs, id)) 3279f920fbSDaniel Mack return cs; 3379f920fbSDaniel Mack } 3479f920fbSDaniel Mack 3579f920fbSDaniel Mack return NULL; 3679f920fbSDaniel Mack } 3779f920fbSDaniel Mack 38f7645bd6STakashi Iwai static bool validate_clock_source_v2(void *p, int id) 399a2fe9b8SRuslan Bilovol { 40f7645bd6STakashi Iwai struct uac_clock_source_descriptor *cs = p; 41b8e4f1fdSTakashi Iwai return cs->bClockID == id; 429a2fe9b8SRuslan Bilovol } 439a2fe9b8SRuslan Bilovol 44f7645bd6STakashi Iwai static bool validate_clock_source_v3(void *p, int id) 4579f920fbSDaniel Mack { 46f7645bd6STakashi Iwai struct uac3_clock_source_descriptor *cs = p; 47b8e4f1fdSTakashi Iwai return cs->bClockID == id; 480a62d6c9STakashi Iwai } 4979f920fbSDaniel Mack 50f7645bd6STakashi Iwai static bool validate_clock_selector_v2(void *p, int id) 519a2fe9b8SRuslan Bilovol { 52f7645bd6STakashi Iwai struct uac_clock_selector_descriptor *cs = p; 53b8e4f1fdSTakashi Iwai return cs->bClockID == id; 549a2fe9b8SRuslan Bilovol } 559a2fe9b8SRuslan Bilovol 56f7645bd6STakashi Iwai static bool validate_clock_selector_v3(void *p, int id) 5779f920fbSDaniel Mack { 58f7645bd6STakashi Iwai struct uac3_clock_selector_descriptor *cs = p; 59b8e4f1fdSTakashi Iwai return cs->bClockID == id; 6079f920fbSDaniel Mack } 6179f920fbSDaniel Mack 62f7645bd6STakashi Iwai static bool validate_clock_multiplier_v2(void *p, int id) 639a2fe9b8SRuslan Bilovol { 64f7645bd6STakashi Iwai struct uac_clock_multiplier_descriptor *cs = p; 65b8e4f1fdSTakashi Iwai return cs->bClockID == id; 669a2fe9b8SRuslan Bilovol } 679a2fe9b8SRuslan Bilovol 68f7645bd6STakashi Iwai static bool validate_clock_multiplier_v3(void *p, int id) 69f7645bd6STakashi Iwai { 70f7645bd6STakashi Iwai struct uac3_clock_multiplier_descriptor *cs = p; 71b8e4f1fdSTakashi Iwai return cs->bClockID == id; 729a2fe9b8SRuslan Bilovol } 739a2fe9b8SRuslan Bilovol 74f7645bd6STakashi Iwai #define DEFINE_FIND_HELPER(name, obj, validator, type) \ 75f7645bd6STakashi Iwai static obj *name(struct usb_host_interface *iface, int id) \ 76f7645bd6STakashi Iwai { \ 77f7645bd6STakashi Iwai return find_uac_clock_desc(iface, id, validator, type); \ 78f7645bd6STakashi Iwai } 79f7645bd6STakashi Iwai 80f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source, 81f7645bd6STakashi Iwai struct uac_clock_source_descriptor, 82f7645bd6STakashi Iwai validate_clock_source_v2, UAC2_CLOCK_SOURCE); 83f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3, 84f7645bd6STakashi Iwai struct uac3_clock_source_descriptor, 85f7645bd6STakashi Iwai validate_clock_source_v3, UAC3_CLOCK_SOURCE); 86f7645bd6STakashi Iwai 87f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector, 88f7645bd6STakashi Iwai struct uac_clock_selector_descriptor, 89f7645bd6STakashi Iwai validate_clock_selector_v2, UAC2_CLOCK_SELECTOR); 90f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3, 91f7645bd6STakashi Iwai struct uac3_clock_selector_descriptor, 92f7645bd6STakashi Iwai validate_clock_selector_v3, UAC3_CLOCK_SELECTOR); 93f7645bd6STakashi Iwai 94f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, 95f7645bd6STakashi Iwai struct uac_clock_multiplier_descriptor, 96f7645bd6STakashi Iwai validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER); 97f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3, 98f7645bd6STakashi Iwai struct uac3_clock_multiplier_descriptor, 99f7645bd6STakashi Iwai validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER); 100f7645bd6STakashi Iwai 10179f920fbSDaniel Mack static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) 10279f920fbSDaniel Mack { 10379f920fbSDaniel Mack unsigned char buf; 10479f920fbSDaniel Mack int ret; 10579f920fbSDaniel Mack 10679f920fbSDaniel Mack ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 10779f920fbSDaniel Mack UAC2_CS_CUR, 10879f920fbSDaniel Mack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 10911bcbc44SDaniel Mack UAC2_CX_CLOCK_SELECTOR << 8, 11011bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (selector_id << 8), 11117d900c4SClemens Ladisch &buf, sizeof(buf)); 11279f920fbSDaniel Mack 11379f920fbSDaniel Mack if (ret < 0) 11479f920fbSDaniel Mack return ret; 11579f920fbSDaniel Mack 11679f920fbSDaniel Mack return buf; 11779f920fbSDaniel Mack } 11879f920fbSDaniel Mack 1198c55af3fSEldad Zack static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, 1208c55af3fSEldad Zack unsigned char pin) 1218c55af3fSEldad Zack { 1228c55af3fSEldad Zack int ret; 1238c55af3fSEldad Zack 1248c55af3fSEldad Zack ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 1258c55af3fSEldad Zack UAC2_CS_CUR, 1268c55af3fSEldad Zack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 1278c55af3fSEldad Zack UAC2_CX_CLOCK_SELECTOR << 8, 1288c55af3fSEldad Zack snd_usb_ctrl_intf(chip) | (selector_id << 8), 1298c55af3fSEldad Zack &pin, sizeof(pin)); 1308c55af3fSEldad Zack if (ret < 0) 1318c55af3fSEldad Zack return ret; 1328c55af3fSEldad Zack 1338c55af3fSEldad Zack if (ret != sizeof(pin)) { 1340ba41d91STakashi Iwai usb_audio_err(chip, 1350ba41d91STakashi Iwai "setting selector (id %d) unexpected length %d\n", 1360ba41d91STakashi Iwai selector_id, ret); 1378c55af3fSEldad Zack return -EINVAL; 1388c55af3fSEldad Zack } 1398c55af3fSEldad Zack 1408c55af3fSEldad Zack ret = uac_clock_selector_get_val(chip, selector_id); 1418c55af3fSEldad Zack if (ret < 0) 1428c55af3fSEldad Zack return ret; 1438c55af3fSEldad Zack 1448c55af3fSEldad Zack if (ret != pin) { 1450ba41d91STakashi Iwai usb_audio_err(chip, 1460ba41d91STakashi Iwai "setting selector (id %d) to %x failed (current: %d)\n", 1470ba41d91STakashi Iwai selector_id, pin, ret); 1488c55af3fSEldad Zack return -EINVAL; 1498c55af3fSEldad Zack } 1508c55af3fSEldad Zack 1518c55af3fSEldad Zack return ret; 1528c55af3fSEldad Zack } 1538c55af3fSEldad Zack 1549a2fe9b8SRuslan Bilovol static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, 1559a2fe9b8SRuslan Bilovol int protocol, 1569a2fe9b8SRuslan Bilovol int source_id) 15779f920fbSDaniel Mack { 15879f920fbSDaniel Mack int err; 15979f920fbSDaniel Mack unsigned char data; 16079f920fbSDaniel Mack struct usb_device *dev = chip->dev; 1619a2fe9b8SRuslan Bilovol u32 bmControls; 1629a2fe9b8SRuslan Bilovol 1639a2fe9b8SRuslan Bilovol if (protocol == UAC_VERSION_3) { 1649a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *cs_desc = 1659a2fe9b8SRuslan Bilovol snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); 1669a2fe9b8SRuslan Bilovol 1679a2fe9b8SRuslan Bilovol if (!cs_desc) 1689a2fe9b8SRuslan Bilovol return 0; 1699a2fe9b8SRuslan Bilovol bmControls = le32_to_cpu(cs_desc->bmControls); 1709a2fe9b8SRuslan Bilovol } else { /* UAC_VERSION_1/2 */ 1713bc6fbc7SDaniel Mack struct uac_clock_source_descriptor *cs_desc = 1723bc6fbc7SDaniel Mack snd_usb_find_clock_source(chip->ctrl_intf, source_id); 1733bc6fbc7SDaniel Mack 1743bc6fbc7SDaniel Mack if (!cs_desc) 1753bc6fbc7SDaniel Mack return 0; 1769a2fe9b8SRuslan Bilovol bmControls = cs_desc->bmControls; 1779a2fe9b8SRuslan Bilovol } 1783bc6fbc7SDaniel Mack 1793bc6fbc7SDaniel Mack /* If a clock source can't tell us whether it's valid, we assume it is */ 1809a2fe9b8SRuslan Bilovol if (!uac_v2v3_control_is_readable(bmControls, 18121e9b3e9SAndrew Chant UAC2_CS_CONTROL_CLOCK_VALID)) 1823bc6fbc7SDaniel Mack return 1; 18379f920fbSDaniel Mack 18479f920fbSDaniel Mack err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 18579f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 18611bcbc44SDaniel Mack UAC2_CS_CONTROL_CLOCK_VALID << 8, 18711bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (source_id << 8), 18817d900c4SClemens Ladisch &data, sizeof(data)); 18979f920fbSDaniel Mack 19079f920fbSDaniel Mack if (err < 0) { 1910ba41d91STakashi Iwai dev_warn(&dev->dev, 1920ba41d91STakashi Iwai "%s(): cannot get clock validity for id %d\n", 19379f920fbSDaniel Mack __func__, source_id); 1943bc6fbc7SDaniel Mack return 0; 19579f920fbSDaniel Mack } 19679f920fbSDaniel Mack 19779f920fbSDaniel Mack return !!data; 19879f920fbSDaniel Mack } 19979f920fbSDaniel Mack 2009a2fe9b8SRuslan Bilovol static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, 2019a2fe9b8SRuslan Bilovol unsigned long *visited, bool validate) 20279f920fbSDaniel Mack { 20379f920fbSDaniel Mack struct uac_clock_source_descriptor *source; 20479f920fbSDaniel Mack struct uac_clock_selector_descriptor *selector; 20579f920fbSDaniel Mack struct uac_clock_multiplier_descriptor *multiplier; 20679f920fbSDaniel Mack 20779f920fbSDaniel Mack entity_id &= 0xff; 20879f920fbSDaniel Mack 20979f920fbSDaniel Mack if (test_and_set_bit(entity_id, visited)) { 2100ba41d91STakashi Iwai usb_audio_warn(chip, 21179f920fbSDaniel Mack "%s(): recursive clock topology detected, id %d.\n", 21279f920fbSDaniel Mack __func__, entity_id); 21379f920fbSDaniel Mack return -EINVAL; 21479f920fbSDaniel Mack } 21579f920fbSDaniel Mack 21679f920fbSDaniel Mack /* first, see if the ID we're looking for is a clock source already */ 2173d8d4dcfSDaniel Mack source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); 21806ffc1ebSEldad Zack if (source) { 21906ffc1ebSEldad Zack entity_id = source->bClockID; 2209a2fe9b8SRuslan Bilovol if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2, 2219a2fe9b8SRuslan Bilovol entity_id)) { 2220ba41d91STakashi Iwai usb_audio_err(chip, 2230ba41d91STakashi Iwai "clock source %d is not valid, cannot use\n", 2240ba41d91STakashi Iwai entity_id); 22506ffc1ebSEldad Zack return -ENXIO; 22606ffc1ebSEldad Zack } 22706ffc1ebSEldad Zack return entity_id; 22806ffc1ebSEldad Zack } 22979f920fbSDaniel Mack 2303d8d4dcfSDaniel Mack selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); 23179f920fbSDaniel Mack if (selector) { 2328c55af3fSEldad Zack int ret, i, cur; 23379f920fbSDaniel Mack 23479f920fbSDaniel Mack /* the entity ID we are looking for is a selector. 23579f920fbSDaniel Mack * find out what it currently selects */ 23679f920fbSDaniel Mack ret = uac_clock_selector_get_val(chip, selector->bClockID); 23779f920fbSDaniel Mack if (ret < 0) 23879f920fbSDaniel Mack return ret; 23979f920fbSDaniel Mack 240157a57b6SDaniel Mack /* Selector values are one-based */ 241157a57b6SDaniel Mack 24279f920fbSDaniel Mack if (ret > selector->bNrInPins || ret < 1) { 2430ba41d91STakashi Iwai usb_audio_err(chip, 24479f920fbSDaniel Mack "%s(): selector reported illegal value, id %d, ret %d\n", 24579f920fbSDaniel Mack __func__, selector->bClockID, ret); 24679f920fbSDaniel Mack 24779f920fbSDaniel Mack return -EINVAL; 24879f920fbSDaniel Mack } 24979f920fbSDaniel Mack 2508c55af3fSEldad Zack cur = ret; 2518c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], 25206ffc1ebSEldad Zack visited, validate); 253ef02e29bSEldad Zack if (!validate || ret > 0 || !chip->autoclock) 2548c55af3fSEldad Zack return ret; 2558c55af3fSEldad Zack 2568c55af3fSEldad Zack /* The current clock source is invalid, try others. */ 2578c55af3fSEldad Zack for (i = 1; i <= selector->bNrInPins; i++) { 2588c55af3fSEldad Zack int err; 2598c55af3fSEldad Zack 2608c55af3fSEldad Zack if (i == cur) 2618c55af3fSEldad Zack continue; 2628c55af3fSEldad Zack 2638c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1], 2648c55af3fSEldad Zack visited, true); 2658c55af3fSEldad Zack if (ret < 0) 2668c55af3fSEldad Zack continue; 2678c55af3fSEldad Zack 2688c55af3fSEldad Zack err = uac_clock_selector_set_val(chip, entity_id, i); 2698c55af3fSEldad Zack if (err < 0) 2708c55af3fSEldad Zack continue; 2718c55af3fSEldad Zack 2720ba41d91STakashi Iwai usb_audio_info(chip, 2730ba41d91STakashi Iwai "found and selected valid clock source %d\n", 2740ba41d91STakashi Iwai ret); 2758c55af3fSEldad Zack return ret; 2768c55af3fSEldad Zack } 2778c55af3fSEldad Zack 2788c55af3fSEldad Zack return -ENXIO; 27979f920fbSDaniel Mack } 28079f920fbSDaniel Mack 28179f920fbSDaniel Mack /* FIXME: multipliers only act as pass-thru element for now */ 2823d8d4dcfSDaniel Mack multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); 28379f920fbSDaniel Mack if (multiplier) 2843d8d4dcfSDaniel Mack return __uac_clock_find_source(chip, multiplier->bCSourceID, 28506ffc1ebSEldad Zack visited, validate); 28679f920fbSDaniel Mack 28779f920fbSDaniel Mack return -EINVAL; 28879f920fbSDaniel Mack } 28979f920fbSDaniel Mack 2909a2fe9b8SRuslan Bilovol static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, 2919a2fe9b8SRuslan Bilovol unsigned long *visited, bool validate) 2929a2fe9b8SRuslan Bilovol { 2939a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *source; 2949a2fe9b8SRuslan Bilovol struct uac3_clock_selector_descriptor *selector; 2959a2fe9b8SRuslan Bilovol struct uac3_clock_multiplier_descriptor *multiplier; 2969a2fe9b8SRuslan Bilovol 2979a2fe9b8SRuslan Bilovol entity_id &= 0xff; 2989a2fe9b8SRuslan Bilovol 2999a2fe9b8SRuslan Bilovol if (test_and_set_bit(entity_id, visited)) { 3009a2fe9b8SRuslan Bilovol usb_audio_warn(chip, 3019a2fe9b8SRuslan Bilovol "%s(): recursive clock topology detected, id %d.\n", 3029a2fe9b8SRuslan Bilovol __func__, entity_id); 3039a2fe9b8SRuslan Bilovol return -EINVAL; 3049a2fe9b8SRuslan Bilovol } 3059a2fe9b8SRuslan Bilovol 3069a2fe9b8SRuslan Bilovol /* first, see if the ID we're looking for is a clock source already */ 3079a2fe9b8SRuslan Bilovol source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); 3089a2fe9b8SRuslan Bilovol if (source) { 3099a2fe9b8SRuslan Bilovol entity_id = source->bClockID; 3109a2fe9b8SRuslan Bilovol if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3, 3119a2fe9b8SRuslan Bilovol entity_id)) { 3129a2fe9b8SRuslan Bilovol usb_audio_err(chip, 3139a2fe9b8SRuslan Bilovol "clock source %d is not valid, cannot use\n", 3149a2fe9b8SRuslan Bilovol entity_id); 3159a2fe9b8SRuslan Bilovol return -ENXIO; 3169a2fe9b8SRuslan Bilovol } 3179a2fe9b8SRuslan Bilovol return entity_id; 3189a2fe9b8SRuslan Bilovol } 3199a2fe9b8SRuslan Bilovol 3209a2fe9b8SRuslan Bilovol selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); 3219a2fe9b8SRuslan Bilovol if (selector) { 3229a2fe9b8SRuslan Bilovol int ret, i, cur; 3239a2fe9b8SRuslan Bilovol 3249a2fe9b8SRuslan Bilovol /* the entity ID we are looking for is a selector. 3259a2fe9b8SRuslan Bilovol * find out what it currently selects */ 3269a2fe9b8SRuslan Bilovol ret = uac_clock_selector_get_val(chip, selector->bClockID); 3279a2fe9b8SRuslan Bilovol if (ret < 0) 3289a2fe9b8SRuslan Bilovol return ret; 3299a2fe9b8SRuslan Bilovol 3309a2fe9b8SRuslan Bilovol /* Selector values are one-based */ 3319a2fe9b8SRuslan Bilovol 3329a2fe9b8SRuslan Bilovol if (ret > selector->bNrInPins || ret < 1) { 3339a2fe9b8SRuslan Bilovol usb_audio_err(chip, 3349a2fe9b8SRuslan Bilovol "%s(): selector reported illegal value, id %d, ret %d\n", 3359a2fe9b8SRuslan Bilovol __func__, selector->bClockID, ret); 3369a2fe9b8SRuslan Bilovol 3379a2fe9b8SRuslan Bilovol return -EINVAL; 3389a2fe9b8SRuslan Bilovol } 3399a2fe9b8SRuslan Bilovol 3409a2fe9b8SRuslan Bilovol cur = ret; 3419a2fe9b8SRuslan Bilovol ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1], 3429a2fe9b8SRuslan Bilovol visited, validate); 3439a2fe9b8SRuslan Bilovol if (!validate || ret > 0 || !chip->autoclock) 3449a2fe9b8SRuslan Bilovol return ret; 3459a2fe9b8SRuslan Bilovol 3469a2fe9b8SRuslan Bilovol /* The current clock source is invalid, try others. */ 3479a2fe9b8SRuslan Bilovol for (i = 1; i <= selector->bNrInPins; i++) { 3489a2fe9b8SRuslan Bilovol int err; 3499a2fe9b8SRuslan Bilovol 3509a2fe9b8SRuslan Bilovol if (i == cur) 3519a2fe9b8SRuslan Bilovol continue; 3529a2fe9b8SRuslan Bilovol 3539a2fe9b8SRuslan Bilovol ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1], 3549a2fe9b8SRuslan Bilovol visited, true); 3559a2fe9b8SRuslan Bilovol if (ret < 0) 3569a2fe9b8SRuslan Bilovol continue; 3579a2fe9b8SRuslan Bilovol 3589a2fe9b8SRuslan Bilovol err = uac_clock_selector_set_val(chip, entity_id, i); 3599a2fe9b8SRuslan Bilovol if (err < 0) 3609a2fe9b8SRuslan Bilovol continue; 3619a2fe9b8SRuslan Bilovol 3629a2fe9b8SRuslan Bilovol usb_audio_info(chip, 3639a2fe9b8SRuslan Bilovol "found and selected valid clock source %d\n", 3649a2fe9b8SRuslan Bilovol ret); 3659a2fe9b8SRuslan Bilovol return ret; 3669a2fe9b8SRuslan Bilovol } 3679a2fe9b8SRuslan Bilovol 3689a2fe9b8SRuslan Bilovol return -ENXIO; 3699a2fe9b8SRuslan Bilovol } 3709a2fe9b8SRuslan Bilovol 3719a2fe9b8SRuslan Bilovol /* FIXME: multipliers only act as pass-thru element for now */ 3729a2fe9b8SRuslan Bilovol multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, 3739a2fe9b8SRuslan Bilovol entity_id); 3749a2fe9b8SRuslan Bilovol if (multiplier) 3759a2fe9b8SRuslan Bilovol return __uac3_clock_find_source(chip, multiplier->bCSourceID, 3769a2fe9b8SRuslan Bilovol visited, validate); 3779a2fe9b8SRuslan Bilovol 3789a2fe9b8SRuslan Bilovol return -EINVAL; 3799a2fe9b8SRuslan Bilovol } 3809a2fe9b8SRuslan Bilovol 381157a57b6SDaniel Mack /* 382157a57b6SDaniel Mack * For all kinds of sample rate settings and other device queries, 383157a57b6SDaniel Mack * the clock source (end-leaf) must be used. However, clock selectors, 384157a57b6SDaniel Mack * clock multipliers and sample rate converters may be specified as 385157a57b6SDaniel Mack * clock source input to terminal. This functions walks the clock path 386157a57b6SDaniel Mack * to its end and tries to find the source. 387157a57b6SDaniel Mack * 388157a57b6SDaniel Mack * The 'visited' bitfield is used internally to detect recursive loops. 389157a57b6SDaniel Mack * 390157a57b6SDaniel Mack * Returns the clock source UnitID (>=0) on success, or an error. 391157a57b6SDaniel Mack */ 3929a2fe9b8SRuslan Bilovol int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, 3939a2fe9b8SRuslan Bilovol int entity_id, bool validate) 39479f920fbSDaniel Mack { 39579f920fbSDaniel Mack DECLARE_BITMAP(visited, 256); 39679f920fbSDaniel Mack memset(visited, 0, sizeof(visited)); 3979a2fe9b8SRuslan Bilovol 3989a2fe9b8SRuslan Bilovol switch (protocol) { 3999a2fe9b8SRuslan Bilovol case UAC_VERSION_2: 4009a2fe9b8SRuslan Bilovol return __uac_clock_find_source(chip, entity_id, visited, 4019a2fe9b8SRuslan Bilovol validate); 4029a2fe9b8SRuslan Bilovol case UAC_VERSION_3: 4039a2fe9b8SRuslan Bilovol return __uac3_clock_find_source(chip, entity_id, visited, 4049a2fe9b8SRuslan Bilovol validate); 4059a2fe9b8SRuslan Bilovol default: 4069a2fe9b8SRuslan Bilovol return -EINVAL; 4079a2fe9b8SRuslan Bilovol } 40879f920fbSDaniel Mack } 40979f920fbSDaniel Mack 41079f920fbSDaniel Mack static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, 41179f920fbSDaniel Mack struct usb_host_interface *alts, 41279f920fbSDaniel Mack struct audioformat *fmt, int rate) 41379f920fbSDaniel Mack { 41479f920fbSDaniel Mack struct usb_device *dev = chip->dev; 41579f920fbSDaniel Mack unsigned int ep; 41679f920fbSDaniel Mack unsigned char data[3]; 41779f920fbSDaniel Mack int err, crate; 41879f920fbSDaniel Mack 419447d6275STakashi Iwai if (get_iface_desc(alts)->bNumEndpoints < 1) 420447d6275STakashi Iwai return -EINVAL; 42179f920fbSDaniel Mack ep = get_endpoint(alts, 0)->bEndpointAddress; 42279f920fbSDaniel Mack 42379f920fbSDaniel Mack /* if endpoint doesn't have sampling rate control, bail out */ 424d32d552eSClemens Ladisch if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) 42579f920fbSDaniel Mack return 0; 42679f920fbSDaniel Mack 42779f920fbSDaniel Mack data[0] = rate; 42879f920fbSDaniel Mack data[1] = rate >> 8; 42979f920fbSDaniel Mack data[2] = rate >> 16; 430f25ecf8fSTakashi Iwai err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 43179f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 43279f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 433f25ecf8fSTakashi Iwai data, sizeof(data)); 434f25ecf8fSTakashi Iwai if (err < 0) { 4350ba41d91STakashi Iwai dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", 4360ba41d91STakashi Iwai iface, fmt->altsetting, rate, ep); 43779f920fbSDaniel Mack return err; 43879f920fbSDaniel Mack } 43979f920fbSDaniel Mack 440b62b9980SJoe Turner /* Don't check the sample rate for devices which we know don't 441b62b9980SJoe Turner * support reading */ 442b62b9980SJoe Turner if (snd_usb_get_sample_rate_quirk(chip)) 443b62b9980SJoe Turner return 0; 44457dd5414STakashi Iwai /* the firmware is likely buggy, don't repeat to fail too many times */ 44557dd5414STakashi Iwai if (chip->sample_rate_read_error > 2) 44657dd5414STakashi Iwai return 0; 447b62b9980SJoe Turner 448f25ecf8fSTakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 44979f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 45079f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 451f25ecf8fSTakashi Iwai data, sizeof(data)); 452f25ecf8fSTakashi Iwai if (err < 0) { 4530ba41d91STakashi Iwai dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", 4540ba41d91STakashi Iwai iface, fmt->altsetting, ep); 45557dd5414STakashi Iwai chip->sample_rate_read_error++; 45679f920fbSDaniel Mack return 0; /* some devices don't support reading */ 45779f920fbSDaniel Mack } 45879f920fbSDaniel Mack 45979f920fbSDaniel Mack crate = data[0] | (data[1] << 8) | (data[2] << 16); 46079f920fbSDaniel Mack if (crate != rate) { 4610ba41d91STakashi Iwai dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate); 46279f920fbSDaniel Mack // runtime->rate = crate; 46379f920fbSDaniel Mack } 46479f920fbSDaniel Mack 46579f920fbSDaniel Mack return 0; 46679f920fbSDaniel Mack } 46779f920fbSDaniel Mack 4689a2fe9b8SRuslan Bilovol static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, 4697c517465STakashi Iwai int altsetting, int clock) 4707c517465STakashi Iwai { 4717c517465STakashi Iwai struct usb_device *dev = chip->dev; 472f6a8bc70SEldad Zack __le32 data; 4737c517465STakashi Iwai int err; 4747c517465STakashi Iwai 4757c517465STakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 4767c517465STakashi Iwai USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 4777c517465STakashi Iwai UAC2_CS_CONTROL_SAM_FREQ << 8, 4787c517465STakashi Iwai snd_usb_ctrl_intf(chip) | (clock << 8), 479f6a8bc70SEldad Zack &data, sizeof(data)); 4807c517465STakashi Iwai if (err < 0) { 4819a2fe9b8SRuslan Bilovol dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", 4820ba41d91STakashi Iwai iface, altsetting, err); 4837c517465STakashi Iwai return 0; 4847c517465STakashi Iwai } 4857c517465STakashi Iwai 486f6a8bc70SEldad Zack return le32_to_cpu(data); 4877c517465STakashi Iwai } 4887c517465STakashi Iwai 4899a2fe9b8SRuslan Bilovol static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, 49079f920fbSDaniel Mack struct usb_host_interface *alts, 49179f920fbSDaniel Mack struct audioformat *fmt, int rate) 49279f920fbSDaniel Mack { 49379f920fbSDaniel Mack struct usb_device *dev = chip->dev; 494f6a8bc70SEldad Zack __le32 data; 495690a863fSTorstein Hegge int err, cur_rate, prev_rate; 4968c55af3fSEldad Zack int clock; 4971dc669feSEldad Zack bool writeable; 4989a2fe9b8SRuslan Bilovol u32 bmControls; 49979f920fbSDaniel Mack 50058cabe87SAdam Goode /* First, try to find a valid clock. This may trigger 50158cabe87SAdam Goode * automatic clock selection if the current clock is not 50258cabe87SAdam Goode * valid. 50358cabe87SAdam Goode */ 5049a2fe9b8SRuslan Bilovol clock = snd_usb_clock_find_source(chip, fmt->protocol, 5059a2fe9b8SRuslan Bilovol fmt->clock, true); 50658cabe87SAdam Goode if (clock < 0) { 50758cabe87SAdam Goode /* We did not find a valid clock, but that might be 50858cabe87SAdam Goode * because the current sample rate does not match an 50958cabe87SAdam Goode * external clock source. Try again without validation 51058cabe87SAdam Goode * and we will do another validation after setting the 51158cabe87SAdam Goode * rate. 51258cabe87SAdam Goode */ 51358cabe87SAdam Goode clock = snd_usb_clock_find_source(chip, fmt->protocol, 51458cabe87SAdam Goode fmt->clock, false); 51579f920fbSDaniel Mack if (clock < 0) 51679f920fbSDaniel Mack return clock; 51758cabe87SAdam Goode } 51879f920fbSDaniel Mack 5199a2fe9b8SRuslan Bilovol prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); 520fa92dd77SDavid Henningsson if (prev_rate == rate) 52158cabe87SAdam Goode goto validation; 522690a863fSTorstein Hegge 5239a2fe9b8SRuslan Bilovol if (fmt->protocol == UAC_VERSION_3) { 5249a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *cs_desc; 5259a2fe9b8SRuslan Bilovol 5269a2fe9b8SRuslan Bilovol cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); 5279a2fe9b8SRuslan Bilovol bmControls = le32_to_cpu(cs_desc->bmControls); 5289a2fe9b8SRuslan Bilovol } else { 5299a2fe9b8SRuslan Bilovol struct uac_clock_source_descriptor *cs_desc; 5309a2fe9b8SRuslan Bilovol 5311dc669feSEldad Zack cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); 5329a2fe9b8SRuslan Bilovol bmControls = cs_desc->bmControls; 5339a2fe9b8SRuslan Bilovol } 5349a2fe9b8SRuslan Bilovol 53521e9b3e9SAndrew Chant writeable = uac_v2v3_control_is_writeable(bmControls, 53621e9b3e9SAndrew Chant UAC2_CS_CONTROL_SAM_FREQ); 5371dc669feSEldad Zack if (writeable) { 538f6a8bc70SEldad Zack data = cpu_to_le32(rate); 5391dc669feSEldad Zack err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 54079f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 54111bcbc44SDaniel Mack UAC2_CS_CONTROL_SAM_FREQ << 8, 54211bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (clock << 8), 5431dc669feSEldad Zack &data, sizeof(data)); 5441dc669feSEldad Zack if (err < 0) { 5450ba41d91STakashi Iwai usb_audio_err(chip, 5469a2fe9b8SRuslan Bilovol "%d:%d: cannot set freq %d (v2/v3): err %d\n", 5470ba41d91STakashi Iwai iface, fmt->altsetting, rate, err); 54879f920fbSDaniel Mack return err; 54979f920fbSDaniel Mack } 55079f920fbSDaniel Mack 5519a2fe9b8SRuslan Bilovol cur_rate = get_sample_rate_v2v3(chip, iface, 5529a2fe9b8SRuslan Bilovol fmt->altsetting, clock); 5531dc669feSEldad Zack } else { 5541dc669feSEldad Zack cur_rate = prev_rate; 5551dc669feSEldad Zack } 55679f920fbSDaniel Mack 557690a863fSTorstein Hegge if (cur_rate != rate) { 5581dc669feSEldad Zack if (!writeable) { 5590ba41d91STakashi Iwai usb_audio_warn(chip, 5600ba41d91STakashi Iwai "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", 5610ba41d91STakashi Iwai iface, fmt->altsetting, rate, cur_rate); 5621dc669feSEldad Zack return -ENXIO; 5631dc669feSEldad Zack } 5640ba41d91STakashi Iwai usb_audio_dbg(chip, 565690a863fSTorstein Hegge "current rate %d is different from the runtime rate %d\n", 566690a863fSTorstein Hegge cur_rate, rate); 567690a863fSTorstein Hegge } 568690a863fSTorstein Hegge 569690a863fSTorstein Hegge /* Some devices doesn't respond to sample rate changes while the 570690a863fSTorstein Hegge * interface is active. */ 571690a863fSTorstein Hegge if (rate != prev_rate) { 572690a863fSTorstein Hegge usb_set_interface(dev, iface, 0); 57321bb5aafSDaniel Mack snd_usb_set_interface_quirk(dev); 574690a863fSTorstein Hegge usb_set_interface(dev, iface, fmt->altsetting); 57521bb5aafSDaniel Mack snd_usb_set_interface_quirk(dev); 576690a863fSTorstein Hegge } 57779f920fbSDaniel Mack 57858cabe87SAdam Goode validation: 57958cabe87SAdam Goode /* validate clock after rate change */ 58058cabe87SAdam Goode if (!uac_clock_source_is_valid(chip, fmt->protocol, clock)) 58158cabe87SAdam Goode return -ENXIO; 58279f920fbSDaniel Mack return 0; 58379f920fbSDaniel Mack } 58479f920fbSDaniel Mack 58579f920fbSDaniel Mack int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, 58679f920fbSDaniel Mack struct usb_host_interface *alts, 58779f920fbSDaniel Mack struct audioformat *fmt, int rate) 58879f920fbSDaniel Mack { 5898f898e92SClemens Ladisch switch (fmt->protocol) { 59079f920fbSDaniel Mack case UAC_VERSION_1: 591a2acad82SClemens Ladisch default: 59279f920fbSDaniel Mack return set_sample_rate_v1(chip, iface, alts, fmt, rate); 59379f920fbSDaniel Mack 5949a2fe9b8SRuslan Bilovol case UAC_VERSION_3: 59517156f23SRuslan Bilovol if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { 59617156f23SRuslan Bilovol if (rate != UAC3_BADD_SAMPLING_RATE) 59717156f23SRuslan Bilovol return -ENXIO; 59817156f23SRuslan Bilovol else 59917156f23SRuslan Bilovol return 0; 60017156f23SRuslan Bilovol } 60117156f23SRuslan Bilovol /* fall through */ 60217156f23SRuslan Bilovol case UAC_VERSION_2: 6039a2fe9b8SRuslan Bilovol return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); 60479f920fbSDaniel Mack } 60579f920fbSDaniel Mack } 60679f920fbSDaniel Mack 607