179f920fbSDaniel Mack /* 279f920fbSDaniel Mack * Clock domain and sample rate management functions 379f920fbSDaniel Mack * 479f920fbSDaniel Mack * This program is free software; you can redistribute it and/or modify 579f920fbSDaniel Mack * it under the terms of the GNU General Public License as published by 679f920fbSDaniel Mack * the Free Software Foundation; either version 2 of the License, or 779f920fbSDaniel Mack * (at your option) any later version. 879f920fbSDaniel Mack * 979f920fbSDaniel Mack * This program is distributed in the hope that it will be useful, 1079f920fbSDaniel Mack * but WITHOUT ANY WARRANTY; without even the implied warranty of 1179f920fbSDaniel Mack * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1279f920fbSDaniel Mack * GNU General Public License for more details. 1379f920fbSDaniel Mack * 1479f920fbSDaniel Mack * You should have received a copy of the GNU General Public License 1579f920fbSDaniel Mack * along with this program; if not, write to the Free Software 1679f920fbSDaniel Mack * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1779f920fbSDaniel Mack * 1879f920fbSDaniel Mack */ 1979f920fbSDaniel Mack 2079f920fbSDaniel Mack #include <linux/bitops.h> 2179f920fbSDaniel Mack #include <linux/init.h> 2279f920fbSDaniel Mack #include <linux/string.h> 2379f920fbSDaniel Mack #include <linux/usb.h> 2479f920fbSDaniel Mack #include <linux/usb/audio.h> 2579f920fbSDaniel Mack #include <linux/usb/audio-v2.h> 269a2fe9b8SRuslan Bilovol #include <linux/usb/audio-v3.h> 2779f920fbSDaniel Mack 2879f920fbSDaniel Mack #include <sound/core.h> 2979f920fbSDaniel Mack #include <sound/info.h> 3079f920fbSDaniel Mack #include <sound/pcm.h> 3179f920fbSDaniel Mack 3279f920fbSDaniel Mack #include "usbaudio.h" 3379f920fbSDaniel Mack #include "card.h" 3479f920fbSDaniel Mack #include "helper.h" 35f22aa949SDaniel Mack #include "clock.h" 3621bb5aafSDaniel Mack #include "quirks.h" 3779f920fbSDaniel Mack 38f7645bd6STakashi Iwai static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, 39f7645bd6STakashi Iwai bool (*validator)(void *, int), u8 type) 4079f920fbSDaniel Mack { 41f7645bd6STakashi Iwai void *cs = NULL; 4279f920fbSDaniel Mack 43f7645bd6STakashi Iwai while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, 44f7645bd6STakashi Iwai cs, type))) { 45f7645bd6STakashi Iwai if (validator(cs, id)) 4679f920fbSDaniel Mack return cs; 4779f920fbSDaniel Mack } 4879f920fbSDaniel Mack 4979f920fbSDaniel Mack return NULL; 5079f920fbSDaniel Mack } 5179f920fbSDaniel Mack 52f7645bd6STakashi Iwai static bool validate_clock_source_v2(void *p, int id) 539a2fe9b8SRuslan Bilovol { 54f7645bd6STakashi Iwai struct uac_clock_source_descriptor *cs = p; 55f5d76e9cSTakashi Iwai return cs->bLength == sizeof(*cs) && cs->bClockID == id; 569a2fe9b8SRuslan Bilovol } 579a2fe9b8SRuslan Bilovol 58f7645bd6STakashi Iwai static bool validate_clock_source_v3(void *p, int id) 5979f920fbSDaniel Mack { 60f7645bd6STakashi Iwai struct uac3_clock_source_descriptor *cs = p; 61b580fbffSTakashi Iwai return cs->bLength == sizeof(*cs) && cs->bClockID == id; 620a62d6c9STakashi Iwai } 6379f920fbSDaniel Mack 64f7645bd6STakashi Iwai static bool validate_clock_selector_v2(void *p, int id) 659a2fe9b8SRuslan Bilovol { 66f7645bd6STakashi Iwai struct uac_clock_selector_descriptor *cs = p; 67f7645bd6STakashi Iwai return cs->bLength >= sizeof(*cs) && cs->bClockID == id && 68f5d76e9cSTakashi Iwai cs->bLength == 7 + cs->bNrInPins; 699a2fe9b8SRuslan Bilovol } 709a2fe9b8SRuslan Bilovol 71f7645bd6STakashi Iwai static bool validate_clock_selector_v3(void *p, int id) 7279f920fbSDaniel Mack { 73f7645bd6STakashi Iwai struct uac3_clock_selector_descriptor *cs = p; 74b580fbffSTakashi Iwai return cs->bLength >= sizeof(*cs) && cs->bClockID == id && 75b580fbffSTakashi Iwai cs->bLength == 11 + cs->bNrInPins; 7679f920fbSDaniel Mack } 7779f920fbSDaniel Mack 78f7645bd6STakashi Iwai static bool validate_clock_multiplier_v2(void *p, int id) 799a2fe9b8SRuslan Bilovol { 80f7645bd6STakashi Iwai struct uac_clock_multiplier_descriptor *cs = p; 81f5d76e9cSTakashi Iwai return cs->bLength == sizeof(*cs) && cs->bClockID == id; 829a2fe9b8SRuslan Bilovol } 839a2fe9b8SRuslan Bilovol 84f7645bd6STakashi Iwai static bool validate_clock_multiplier_v3(void *p, int id) 85f7645bd6STakashi Iwai { 86f7645bd6STakashi Iwai struct uac3_clock_multiplier_descriptor *cs = p; 87b580fbffSTakashi Iwai return cs->bLength == sizeof(*cs) && cs->bClockID == id; 889a2fe9b8SRuslan Bilovol } 899a2fe9b8SRuslan Bilovol 90f7645bd6STakashi Iwai #define DEFINE_FIND_HELPER(name, obj, validator, type) \ 91f7645bd6STakashi Iwai static obj *name(struct usb_host_interface *iface, int id) \ 92f7645bd6STakashi Iwai { \ 93f7645bd6STakashi Iwai return find_uac_clock_desc(iface, id, validator, type); \ 94f7645bd6STakashi Iwai } 95f7645bd6STakashi Iwai 96f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source, 97f7645bd6STakashi Iwai struct uac_clock_source_descriptor, 98f7645bd6STakashi Iwai validate_clock_source_v2, UAC2_CLOCK_SOURCE); 99f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3, 100f7645bd6STakashi Iwai struct uac3_clock_source_descriptor, 101f7645bd6STakashi Iwai validate_clock_source_v3, UAC3_CLOCK_SOURCE); 102f7645bd6STakashi Iwai 103f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector, 104f7645bd6STakashi Iwai struct uac_clock_selector_descriptor, 105f7645bd6STakashi Iwai validate_clock_selector_v2, UAC2_CLOCK_SELECTOR); 106f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3, 107f7645bd6STakashi Iwai struct uac3_clock_selector_descriptor, 108f7645bd6STakashi Iwai validate_clock_selector_v3, UAC3_CLOCK_SELECTOR); 109f7645bd6STakashi Iwai 110f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, 111f7645bd6STakashi Iwai struct uac_clock_multiplier_descriptor, 112f7645bd6STakashi Iwai validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER); 113f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3, 114f7645bd6STakashi Iwai struct uac3_clock_multiplier_descriptor, 115f7645bd6STakashi Iwai validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER); 116f7645bd6STakashi Iwai 11779f920fbSDaniel Mack static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) 11879f920fbSDaniel Mack { 11979f920fbSDaniel Mack unsigned char buf; 12079f920fbSDaniel Mack int ret; 12179f920fbSDaniel Mack 12279f920fbSDaniel Mack ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 12379f920fbSDaniel Mack UAC2_CS_CUR, 12479f920fbSDaniel Mack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 12511bcbc44SDaniel Mack UAC2_CX_CLOCK_SELECTOR << 8, 12611bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (selector_id << 8), 12717d900c4SClemens Ladisch &buf, sizeof(buf)); 12879f920fbSDaniel Mack 12979f920fbSDaniel Mack if (ret < 0) 13079f920fbSDaniel Mack return ret; 13179f920fbSDaniel Mack 13279f920fbSDaniel Mack return buf; 13379f920fbSDaniel Mack } 13479f920fbSDaniel Mack 1358c55af3fSEldad Zack static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, 1368c55af3fSEldad Zack unsigned char pin) 1378c55af3fSEldad Zack { 1388c55af3fSEldad Zack int ret; 1398c55af3fSEldad Zack 1408c55af3fSEldad Zack ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 1418c55af3fSEldad Zack UAC2_CS_CUR, 1428c55af3fSEldad Zack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 1438c55af3fSEldad Zack UAC2_CX_CLOCK_SELECTOR << 8, 1448c55af3fSEldad Zack snd_usb_ctrl_intf(chip) | (selector_id << 8), 1458c55af3fSEldad Zack &pin, sizeof(pin)); 1468c55af3fSEldad Zack if (ret < 0) 1478c55af3fSEldad Zack return ret; 1488c55af3fSEldad Zack 1498c55af3fSEldad Zack if (ret != sizeof(pin)) { 1500ba41d91STakashi Iwai usb_audio_err(chip, 1510ba41d91STakashi Iwai "setting selector (id %d) unexpected length %d\n", 1520ba41d91STakashi Iwai selector_id, ret); 1538c55af3fSEldad Zack return -EINVAL; 1548c55af3fSEldad Zack } 1558c55af3fSEldad Zack 1568c55af3fSEldad Zack ret = uac_clock_selector_get_val(chip, selector_id); 1578c55af3fSEldad Zack if (ret < 0) 1588c55af3fSEldad Zack return ret; 1598c55af3fSEldad Zack 1608c55af3fSEldad Zack if (ret != pin) { 1610ba41d91STakashi Iwai usb_audio_err(chip, 1620ba41d91STakashi Iwai "setting selector (id %d) to %x failed (current: %d)\n", 1630ba41d91STakashi Iwai selector_id, pin, ret); 1648c55af3fSEldad Zack return -EINVAL; 1658c55af3fSEldad Zack } 1668c55af3fSEldad Zack 1678c55af3fSEldad Zack return ret; 1688c55af3fSEldad Zack } 1698c55af3fSEldad Zack 1709a2fe9b8SRuslan Bilovol static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, 1719a2fe9b8SRuslan Bilovol int protocol, 1729a2fe9b8SRuslan Bilovol int source_id) 17379f920fbSDaniel Mack { 17479f920fbSDaniel Mack int err; 17579f920fbSDaniel Mack unsigned char data; 17679f920fbSDaniel Mack struct usb_device *dev = chip->dev; 1779a2fe9b8SRuslan Bilovol u32 bmControls; 1789a2fe9b8SRuslan Bilovol 1799a2fe9b8SRuslan Bilovol if (protocol == UAC_VERSION_3) { 1809a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *cs_desc = 1819a2fe9b8SRuslan Bilovol snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); 1829a2fe9b8SRuslan Bilovol 1839a2fe9b8SRuslan Bilovol if (!cs_desc) 1849a2fe9b8SRuslan Bilovol return 0; 1859a2fe9b8SRuslan Bilovol bmControls = le32_to_cpu(cs_desc->bmControls); 1869a2fe9b8SRuslan Bilovol } else { /* UAC_VERSION_1/2 */ 1873bc6fbc7SDaniel Mack struct uac_clock_source_descriptor *cs_desc = 1883bc6fbc7SDaniel Mack snd_usb_find_clock_source(chip->ctrl_intf, source_id); 1893bc6fbc7SDaniel Mack 1903bc6fbc7SDaniel Mack if (!cs_desc) 1913bc6fbc7SDaniel Mack return 0; 1929a2fe9b8SRuslan Bilovol bmControls = cs_desc->bmControls; 1939a2fe9b8SRuslan Bilovol } 1943bc6fbc7SDaniel Mack 1953bc6fbc7SDaniel Mack /* If a clock source can't tell us whether it's valid, we assume it is */ 1969a2fe9b8SRuslan Bilovol if (!uac_v2v3_control_is_readable(bmControls, 19721e9b3e9SAndrew Chant UAC2_CS_CONTROL_CLOCK_VALID)) 1983bc6fbc7SDaniel Mack return 1; 19979f920fbSDaniel Mack 20079f920fbSDaniel Mack err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 20179f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 20211bcbc44SDaniel Mack UAC2_CS_CONTROL_CLOCK_VALID << 8, 20311bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (source_id << 8), 20417d900c4SClemens Ladisch &data, sizeof(data)); 20579f920fbSDaniel Mack 20679f920fbSDaniel Mack if (err < 0) { 2070ba41d91STakashi Iwai dev_warn(&dev->dev, 2080ba41d91STakashi Iwai "%s(): cannot get clock validity for id %d\n", 20979f920fbSDaniel Mack __func__, source_id); 2103bc6fbc7SDaniel Mack return 0; 21179f920fbSDaniel Mack } 21279f920fbSDaniel Mack 21379f920fbSDaniel Mack return !!data; 21479f920fbSDaniel Mack } 21579f920fbSDaniel Mack 2169a2fe9b8SRuslan Bilovol static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, 2179a2fe9b8SRuslan Bilovol unsigned long *visited, bool validate) 21879f920fbSDaniel Mack { 21979f920fbSDaniel Mack struct uac_clock_source_descriptor *source; 22079f920fbSDaniel Mack struct uac_clock_selector_descriptor *selector; 22179f920fbSDaniel Mack struct uac_clock_multiplier_descriptor *multiplier; 22279f920fbSDaniel Mack 22379f920fbSDaniel Mack entity_id &= 0xff; 22479f920fbSDaniel Mack 22579f920fbSDaniel Mack if (test_and_set_bit(entity_id, visited)) { 2260ba41d91STakashi Iwai usb_audio_warn(chip, 22779f920fbSDaniel Mack "%s(): recursive clock topology detected, id %d.\n", 22879f920fbSDaniel Mack __func__, entity_id); 22979f920fbSDaniel Mack return -EINVAL; 23079f920fbSDaniel Mack } 23179f920fbSDaniel Mack 23279f920fbSDaniel Mack /* first, see if the ID we're looking for is a clock source already */ 2333d8d4dcfSDaniel Mack source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); 23406ffc1ebSEldad Zack if (source) { 23506ffc1ebSEldad Zack entity_id = source->bClockID; 2369a2fe9b8SRuslan Bilovol if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2, 2379a2fe9b8SRuslan Bilovol entity_id)) { 2380ba41d91STakashi Iwai usb_audio_err(chip, 2390ba41d91STakashi Iwai "clock source %d is not valid, cannot use\n", 2400ba41d91STakashi Iwai entity_id); 24106ffc1ebSEldad Zack return -ENXIO; 24206ffc1ebSEldad Zack } 24306ffc1ebSEldad Zack return entity_id; 24406ffc1ebSEldad Zack } 24579f920fbSDaniel Mack 2463d8d4dcfSDaniel Mack selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); 24779f920fbSDaniel Mack if (selector) { 2488c55af3fSEldad Zack int ret, i, cur; 24979f920fbSDaniel Mack 25079f920fbSDaniel Mack /* the entity ID we are looking for is a selector. 25179f920fbSDaniel Mack * find out what it currently selects */ 25279f920fbSDaniel Mack ret = uac_clock_selector_get_val(chip, selector->bClockID); 25379f920fbSDaniel Mack if (ret < 0) 25479f920fbSDaniel Mack return ret; 25579f920fbSDaniel Mack 256157a57b6SDaniel Mack /* Selector values are one-based */ 257157a57b6SDaniel Mack 25879f920fbSDaniel Mack if (ret > selector->bNrInPins || ret < 1) { 2590ba41d91STakashi Iwai usb_audio_err(chip, 26079f920fbSDaniel Mack "%s(): selector reported illegal value, id %d, ret %d\n", 26179f920fbSDaniel Mack __func__, selector->bClockID, ret); 26279f920fbSDaniel Mack 26379f920fbSDaniel Mack return -EINVAL; 26479f920fbSDaniel Mack } 26579f920fbSDaniel Mack 2668c55af3fSEldad Zack cur = ret; 2678c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], 26806ffc1ebSEldad Zack visited, validate); 269ef02e29bSEldad Zack if (!validate || ret > 0 || !chip->autoclock) 2708c55af3fSEldad Zack return ret; 2718c55af3fSEldad Zack 2728c55af3fSEldad Zack /* The current clock source is invalid, try others. */ 2738c55af3fSEldad Zack for (i = 1; i <= selector->bNrInPins; i++) { 2748c55af3fSEldad Zack int err; 2758c55af3fSEldad Zack 2768c55af3fSEldad Zack if (i == cur) 2778c55af3fSEldad Zack continue; 2788c55af3fSEldad Zack 2798c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1], 2808c55af3fSEldad Zack visited, true); 2818c55af3fSEldad Zack if (ret < 0) 2828c55af3fSEldad Zack continue; 2838c55af3fSEldad Zack 2848c55af3fSEldad Zack err = uac_clock_selector_set_val(chip, entity_id, i); 2858c55af3fSEldad Zack if (err < 0) 2868c55af3fSEldad Zack continue; 2878c55af3fSEldad Zack 2880ba41d91STakashi Iwai usb_audio_info(chip, 2890ba41d91STakashi Iwai "found and selected valid clock source %d\n", 2900ba41d91STakashi Iwai ret); 2918c55af3fSEldad Zack return ret; 2928c55af3fSEldad Zack } 2938c55af3fSEldad Zack 2948c55af3fSEldad Zack return -ENXIO; 29579f920fbSDaniel Mack } 29679f920fbSDaniel Mack 29779f920fbSDaniel Mack /* FIXME: multipliers only act as pass-thru element for now */ 2983d8d4dcfSDaniel Mack multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); 29979f920fbSDaniel Mack if (multiplier) 3003d8d4dcfSDaniel Mack return __uac_clock_find_source(chip, multiplier->bCSourceID, 30106ffc1ebSEldad Zack visited, validate); 30279f920fbSDaniel Mack 30379f920fbSDaniel Mack return -EINVAL; 30479f920fbSDaniel Mack } 30579f920fbSDaniel Mack 3069a2fe9b8SRuslan Bilovol static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, 3079a2fe9b8SRuslan Bilovol unsigned long *visited, bool validate) 3089a2fe9b8SRuslan Bilovol { 3099a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *source; 3109a2fe9b8SRuslan Bilovol struct uac3_clock_selector_descriptor *selector; 3119a2fe9b8SRuslan Bilovol struct uac3_clock_multiplier_descriptor *multiplier; 3129a2fe9b8SRuslan Bilovol 3139a2fe9b8SRuslan Bilovol entity_id &= 0xff; 3149a2fe9b8SRuslan Bilovol 3159a2fe9b8SRuslan Bilovol if (test_and_set_bit(entity_id, visited)) { 3169a2fe9b8SRuslan Bilovol usb_audio_warn(chip, 3179a2fe9b8SRuslan Bilovol "%s(): recursive clock topology detected, id %d.\n", 3189a2fe9b8SRuslan Bilovol __func__, entity_id); 3199a2fe9b8SRuslan Bilovol return -EINVAL; 3209a2fe9b8SRuslan Bilovol } 3219a2fe9b8SRuslan Bilovol 3229a2fe9b8SRuslan Bilovol /* first, see if the ID we're looking for is a clock source already */ 3239a2fe9b8SRuslan Bilovol source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); 3249a2fe9b8SRuslan Bilovol if (source) { 3259a2fe9b8SRuslan Bilovol entity_id = source->bClockID; 3269a2fe9b8SRuslan Bilovol if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3, 3279a2fe9b8SRuslan Bilovol entity_id)) { 3289a2fe9b8SRuslan Bilovol usb_audio_err(chip, 3299a2fe9b8SRuslan Bilovol "clock source %d is not valid, cannot use\n", 3309a2fe9b8SRuslan Bilovol entity_id); 3319a2fe9b8SRuslan Bilovol return -ENXIO; 3329a2fe9b8SRuslan Bilovol } 3339a2fe9b8SRuslan Bilovol return entity_id; 3349a2fe9b8SRuslan Bilovol } 3359a2fe9b8SRuslan Bilovol 3369a2fe9b8SRuslan Bilovol selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); 3379a2fe9b8SRuslan Bilovol if (selector) { 3389a2fe9b8SRuslan Bilovol int ret, i, cur; 3399a2fe9b8SRuslan Bilovol 3409a2fe9b8SRuslan Bilovol /* the entity ID we are looking for is a selector. 3419a2fe9b8SRuslan Bilovol * find out what it currently selects */ 3429a2fe9b8SRuslan Bilovol ret = uac_clock_selector_get_val(chip, selector->bClockID); 3439a2fe9b8SRuslan Bilovol if (ret < 0) 3449a2fe9b8SRuslan Bilovol return ret; 3459a2fe9b8SRuslan Bilovol 3469a2fe9b8SRuslan Bilovol /* Selector values are one-based */ 3479a2fe9b8SRuslan Bilovol 3489a2fe9b8SRuslan Bilovol if (ret > selector->bNrInPins || ret < 1) { 3499a2fe9b8SRuslan Bilovol usb_audio_err(chip, 3509a2fe9b8SRuslan Bilovol "%s(): selector reported illegal value, id %d, ret %d\n", 3519a2fe9b8SRuslan Bilovol __func__, selector->bClockID, ret); 3529a2fe9b8SRuslan Bilovol 3539a2fe9b8SRuslan Bilovol return -EINVAL; 3549a2fe9b8SRuslan Bilovol } 3559a2fe9b8SRuslan Bilovol 3569a2fe9b8SRuslan Bilovol cur = ret; 3579a2fe9b8SRuslan Bilovol ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1], 3589a2fe9b8SRuslan Bilovol visited, validate); 3599a2fe9b8SRuslan Bilovol if (!validate || ret > 0 || !chip->autoclock) 3609a2fe9b8SRuslan Bilovol return ret; 3619a2fe9b8SRuslan Bilovol 3629a2fe9b8SRuslan Bilovol /* The current clock source is invalid, try others. */ 3639a2fe9b8SRuslan Bilovol for (i = 1; i <= selector->bNrInPins; i++) { 3649a2fe9b8SRuslan Bilovol int err; 3659a2fe9b8SRuslan Bilovol 3669a2fe9b8SRuslan Bilovol if (i == cur) 3679a2fe9b8SRuslan Bilovol continue; 3689a2fe9b8SRuslan Bilovol 3699a2fe9b8SRuslan Bilovol ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1], 3709a2fe9b8SRuslan Bilovol visited, true); 3719a2fe9b8SRuslan Bilovol if (ret < 0) 3729a2fe9b8SRuslan Bilovol continue; 3739a2fe9b8SRuslan Bilovol 3749a2fe9b8SRuslan Bilovol err = uac_clock_selector_set_val(chip, entity_id, i); 3759a2fe9b8SRuslan Bilovol if (err < 0) 3769a2fe9b8SRuslan Bilovol continue; 3779a2fe9b8SRuslan Bilovol 3789a2fe9b8SRuslan Bilovol usb_audio_info(chip, 3799a2fe9b8SRuslan Bilovol "found and selected valid clock source %d\n", 3809a2fe9b8SRuslan Bilovol ret); 3819a2fe9b8SRuslan Bilovol return ret; 3829a2fe9b8SRuslan Bilovol } 3839a2fe9b8SRuslan Bilovol 3849a2fe9b8SRuslan Bilovol return -ENXIO; 3859a2fe9b8SRuslan Bilovol } 3869a2fe9b8SRuslan Bilovol 3879a2fe9b8SRuslan Bilovol /* FIXME: multipliers only act as pass-thru element for now */ 3889a2fe9b8SRuslan Bilovol multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, 3899a2fe9b8SRuslan Bilovol entity_id); 3909a2fe9b8SRuslan Bilovol if (multiplier) 3919a2fe9b8SRuslan Bilovol return __uac3_clock_find_source(chip, multiplier->bCSourceID, 3929a2fe9b8SRuslan Bilovol visited, validate); 3939a2fe9b8SRuslan Bilovol 3949a2fe9b8SRuslan Bilovol return -EINVAL; 3959a2fe9b8SRuslan Bilovol } 3969a2fe9b8SRuslan Bilovol 397157a57b6SDaniel Mack /* 398157a57b6SDaniel Mack * For all kinds of sample rate settings and other device queries, 399157a57b6SDaniel Mack * the clock source (end-leaf) must be used. However, clock selectors, 400157a57b6SDaniel Mack * clock multipliers and sample rate converters may be specified as 401157a57b6SDaniel Mack * clock source input to terminal. This functions walks the clock path 402157a57b6SDaniel Mack * to its end and tries to find the source. 403157a57b6SDaniel Mack * 404157a57b6SDaniel Mack * The 'visited' bitfield is used internally to detect recursive loops. 405157a57b6SDaniel Mack * 406157a57b6SDaniel Mack * Returns the clock source UnitID (>=0) on success, or an error. 407157a57b6SDaniel Mack */ 4089a2fe9b8SRuslan Bilovol int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, 4099a2fe9b8SRuslan Bilovol int entity_id, bool validate) 41079f920fbSDaniel Mack { 41179f920fbSDaniel Mack DECLARE_BITMAP(visited, 256); 41279f920fbSDaniel Mack memset(visited, 0, sizeof(visited)); 4139a2fe9b8SRuslan Bilovol 4149a2fe9b8SRuslan Bilovol switch (protocol) { 4159a2fe9b8SRuslan Bilovol case UAC_VERSION_2: 4169a2fe9b8SRuslan Bilovol return __uac_clock_find_source(chip, entity_id, visited, 4179a2fe9b8SRuslan Bilovol validate); 4189a2fe9b8SRuslan Bilovol case UAC_VERSION_3: 4199a2fe9b8SRuslan Bilovol return __uac3_clock_find_source(chip, entity_id, visited, 4209a2fe9b8SRuslan Bilovol validate); 4219a2fe9b8SRuslan Bilovol default: 4229a2fe9b8SRuslan Bilovol return -EINVAL; 4239a2fe9b8SRuslan Bilovol } 42479f920fbSDaniel Mack } 42579f920fbSDaniel Mack 42679f920fbSDaniel Mack static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, 42779f920fbSDaniel Mack struct usb_host_interface *alts, 42879f920fbSDaniel Mack struct audioformat *fmt, int rate) 42979f920fbSDaniel Mack { 43079f920fbSDaniel Mack struct usb_device *dev = chip->dev; 43179f920fbSDaniel Mack unsigned int ep; 43279f920fbSDaniel Mack unsigned char data[3]; 43379f920fbSDaniel Mack int err, crate; 43479f920fbSDaniel Mack 435447d6275STakashi Iwai if (get_iface_desc(alts)->bNumEndpoints < 1) 436447d6275STakashi Iwai return -EINVAL; 43779f920fbSDaniel Mack ep = get_endpoint(alts, 0)->bEndpointAddress; 43879f920fbSDaniel Mack 43979f920fbSDaniel Mack /* if endpoint doesn't have sampling rate control, bail out */ 440d32d552eSClemens Ladisch if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) 44179f920fbSDaniel Mack return 0; 44279f920fbSDaniel Mack 44379f920fbSDaniel Mack data[0] = rate; 44479f920fbSDaniel Mack data[1] = rate >> 8; 44579f920fbSDaniel Mack data[2] = rate >> 16; 446f25ecf8fSTakashi Iwai err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 44779f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 44879f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 449f25ecf8fSTakashi Iwai data, sizeof(data)); 450f25ecf8fSTakashi Iwai if (err < 0) { 4510ba41d91STakashi Iwai dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", 4520ba41d91STakashi Iwai iface, fmt->altsetting, rate, ep); 45379f920fbSDaniel Mack return err; 45479f920fbSDaniel Mack } 45579f920fbSDaniel Mack 456b62b9980SJoe Turner /* Don't check the sample rate for devices which we know don't 457b62b9980SJoe Turner * support reading */ 458b62b9980SJoe Turner if (snd_usb_get_sample_rate_quirk(chip)) 459b62b9980SJoe Turner return 0; 46057dd5414STakashi Iwai /* the firmware is likely buggy, don't repeat to fail too many times */ 46157dd5414STakashi Iwai if (chip->sample_rate_read_error > 2) 46257dd5414STakashi Iwai return 0; 463b62b9980SJoe Turner 464f25ecf8fSTakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 46579f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 46679f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 467f25ecf8fSTakashi Iwai data, sizeof(data)); 468f25ecf8fSTakashi Iwai if (err < 0) { 4690ba41d91STakashi Iwai dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", 4700ba41d91STakashi Iwai iface, fmt->altsetting, ep); 47157dd5414STakashi Iwai chip->sample_rate_read_error++; 47279f920fbSDaniel Mack return 0; /* some devices don't support reading */ 47379f920fbSDaniel Mack } 47479f920fbSDaniel Mack 47579f920fbSDaniel Mack crate = data[0] | (data[1] << 8) | (data[2] << 16); 47679f920fbSDaniel Mack if (crate != rate) { 4770ba41d91STakashi Iwai dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate); 47879f920fbSDaniel Mack // runtime->rate = crate; 47979f920fbSDaniel Mack } 48079f920fbSDaniel Mack 48179f920fbSDaniel Mack return 0; 48279f920fbSDaniel Mack } 48379f920fbSDaniel Mack 4849a2fe9b8SRuslan Bilovol static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, 4857c517465STakashi Iwai int altsetting, int clock) 4867c517465STakashi Iwai { 4877c517465STakashi Iwai struct usb_device *dev = chip->dev; 488f6a8bc70SEldad Zack __le32 data; 4897c517465STakashi Iwai int err; 4907c517465STakashi Iwai 4917c517465STakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 4927c517465STakashi Iwai USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 4937c517465STakashi Iwai UAC2_CS_CONTROL_SAM_FREQ << 8, 4947c517465STakashi Iwai snd_usb_ctrl_intf(chip) | (clock << 8), 495f6a8bc70SEldad Zack &data, sizeof(data)); 4967c517465STakashi Iwai if (err < 0) { 4979a2fe9b8SRuslan Bilovol dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", 4980ba41d91STakashi Iwai iface, altsetting, err); 4997c517465STakashi Iwai return 0; 5007c517465STakashi Iwai } 5017c517465STakashi Iwai 502f6a8bc70SEldad Zack return le32_to_cpu(data); 5037c517465STakashi Iwai } 5047c517465STakashi Iwai 5059a2fe9b8SRuslan Bilovol static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, 50679f920fbSDaniel Mack struct usb_host_interface *alts, 50779f920fbSDaniel Mack struct audioformat *fmt, int rate) 50879f920fbSDaniel Mack { 50979f920fbSDaniel Mack struct usb_device *dev = chip->dev; 510f6a8bc70SEldad Zack __le32 data; 511690a863fSTorstein Hegge int err, cur_rate, prev_rate; 5128c55af3fSEldad Zack int clock; 5131dc669feSEldad Zack bool writeable; 5149a2fe9b8SRuslan Bilovol u32 bmControls; 51579f920fbSDaniel Mack 5169a2fe9b8SRuslan Bilovol clock = snd_usb_clock_find_source(chip, fmt->protocol, 5179a2fe9b8SRuslan Bilovol fmt->clock, true); 51879f920fbSDaniel Mack if (clock < 0) 51979f920fbSDaniel Mack return clock; 52079f920fbSDaniel Mack 5219a2fe9b8SRuslan Bilovol prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); 522fa92dd77SDavid Henningsson if (prev_rate == rate) 523fa92dd77SDavid Henningsson return 0; 524690a863fSTorstein Hegge 5259a2fe9b8SRuslan Bilovol if (fmt->protocol == UAC_VERSION_3) { 5269a2fe9b8SRuslan Bilovol struct uac3_clock_source_descriptor *cs_desc; 5279a2fe9b8SRuslan Bilovol 5289a2fe9b8SRuslan Bilovol cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); 5299a2fe9b8SRuslan Bilovol bmControls = le32_to_cpu(cs_desc->bmControls); 5309a2fe9b8SRuslan Bilovol } else { 5319a2fe9b8SRuslan Bilovol struct uac_clock_source_descriptor *cs_desc; 5329a2fe9b8SRuslan Bilovol 5331dc669feSEldad Zack cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); 5349a2fe9b8SRuslan Bilovol bmControls = cs_desc->bmControls; 5359a2fe9b8SRuslan Bilovol } 5369a2fe9b8SRuslan Bilovol 53721e9b3e9SAndrew Chant writeable = uac_v2v3_control_is_writeable(bmControls, 53821e9b3e9SAndrew Chant UAC2_CS_CONTROL_SAM_FREQ); 5391dc669feSEldad Zack if (writeable) { 540f6a8bc70SEldad Zack data = cpu_to_le32(rate); 5411dc669feSEldad Zack err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 54279f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 54311bcbc44SDaniel Mack UAC2_CS_CONTROL_SAM_FREQ << 8, 54411bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (clock << 8), 5451dc669feSEldad Zack &data, sizeof(data)); 5461dc669feSEldad Zack if (err < 0) { 5470ba41d91STakashi Iwai usb_audio_err(chip, 5489a2fe9b8SRuslan Bilovol "%d:%d: cannot set freq %d (v2/v3): err %d\n", 5490ba41d91STakashi Iwai iface, fmt->altsetting, rate, err); 55079f920fbSDaniel Mack return err; 55179f920fbSDaniel Mack } 55279f920fbSDaniel Mack 5539a2fe9b8SRuslan Bilovol cur_rate = get_sample_rate_v2v3(chip, iface, 5549a2fe9b8SRuslan Bilovol fmt->altsetting, clock); 5551dc669feSEldad Zack } else { 5561dc669feSEldad Zack cur_rate = prev_rate; 5571dc669feSEldad Zack } 55879f920fbSDaniel Mack 559690a863fSTorstein Hegge if (cur_rate != rate) { 5601dc669feSEldad Zack if (!writeable) { 5610ba41d91STakashi Iwai usb_audio_warn(chip, 5620ba41d91STakashi Iwai "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", 5630ba41d91STakashi Iwai iface, fmt->altsetting, rate, cur_rate); 5641dc669feSEldad Zack return -ENXIO; 5651dc669feSEldad Zack } 5660ba41d91STakashi Iwai usb_audio_dbg(chip, 567690a863fSTorstein Hegge "current rate %d is different from the runtime rate %d\n", 568690a863fSTorstein Hegge cur_rate, rate); 569690a863fSTorstein Hegge } 570690a863fSTorstein Hegge 571690a863fSTorstein Hegge /* Some devices doesn't respond to sample rate changes while the 572690a863fSTorstein Hegge * interface is active. */ 573690a863fSTorstein Hegge if (rate != prev_rate) { 574690a863fSTorstein Hegge usb_set_interface(dev, iface, 0); 57521bb5aafSDaniel Mack snd_usb_set_interface_quirk(dev); 576690a863fSTorstein Hegge usb_set_interface(dev, iface, fmt->altsetting); 57721bb5aafSDaniel Mack snd_usb_set_interface_quirk(dev); 578690a863fSTorstein Hegge } 57979f920fbSDaniel Mack 58079f920fbSDaniel Mack return 0; 58179f920fbSDaniel Mack } 58279f920fbSDaniel Mack 58379f920fbSDaniel Mack int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, 58479f920fbSDaniel Mack struct usb_host_interface *alts, 58579f920fbSDaniel Mack struct audioformat *fmt, int rate) 58679f920fbSDaniel Mack { 5878f898e92SClemens Ladisch switch (fmt->protocol) { 58879f920fbSDaniel Mack case UAC_VERSION_1: 589a2acad82SClemens Ladisch default: 59079f920fbSDaniel Mack return set_sample_rate_v1(chip, iface, alts, fmt, rate); 59179f920fbSDaniel Mack 5929a2fe9b8SRuslan Bilovol case UAC_VERSION_3: 59317156f23SRuslan Bilovol if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { 59417156f23SRuslan Bilovol if (rate != UAC3_BADD_SAMPLING_RATE) 59517156f23SRuslan Bilovol return -ENXIO; 59617156f23SRuslan Bilovol else 59717156f23SRuslan Bilovol return 0; 59817156f23SRuslan Bilovol } 59917156f23SRuslan Bilovol /* fall through */ 60017156f23SRuslan Bilovol case UAC_VERSION_2: 6019a2fe9b8SRuslan Bilovol return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); 60279f920fbSDaniel Mack } 60379f920fbSDaniel Mack } 60479f920fbSDaniel Mack 605