162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Clock domain and sample rate management functions 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/bitops.h> 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/string.h> 962306a36Sopenharmony_ci#include <linux/usb.h> 1062306a36Sopenharmony_ci#include <linux/usb/audio.h> 1162306a36Sopenharmony_ci#include <linux/usb/audio-v2.h> 1262306a36Sopenharmony_ci#include <linux/usb/audio-v3.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <sound/core.h> 1562306a36Sopenharmony_ci#include <sound/info.h> 1662306a36Sopenharmony_ci#include <sound/pcm.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "usbaudio.h" 1962306a36Sopenharmony_ci#include "card.h" 2062306a36Sopenharmony_ci#include "helper.h" 2162306a36Sopenharmony_ci#include "clock.h" 2262306a36Sopenharmony_ci#include "quirks.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciunion uac23_clock_source_desc { 2562306a36Sopenharmony_ci struct uac_clock_source_descriptor v2; 2662306a36Sopenharmony_ci struct uac3_clock_source_descriptor v3; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciunion uac23_clock_selector_desc { 3062306a36Sopenharmony_ci struct uac_clock_selector_descriptor v2; 3162306a36Sopenharmony_ci struct uac3_clock_selector_descriptor v3; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciunion uac23_clock_multiplier_desc { 3562306a36Sopenharmony_ci struct uac_clock_multiplier_descriptor v2; 3662306a36Sopenharmony_ci struct uac_clock_multiplier_descriptor v3; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define GET_VAL(p, proto, field) \ 4062306a36Sopenharmony_ci ((proto) == UAC_VERSION_3 ? (p)->v3.field : (p)->v2.field) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void *find_uac_clock_desc(struct usb_host_interface *iface, int id, 4362306a36Sopenharmony_ci bool (*validator)(void *, int, int), 4462306a36Sopenharmony_ci u8 type, int proto) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci void *cs = NULL; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, 4962306a36Sopenharmony_ci cs, type))) { 5062306a36Sopenharmony_ci if (validator(cs, id, proto)) 5162306a36Sopenharmony_ci return cs; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return NULL; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic bool validate_clock_source(void *p, int id, int proto) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci union uac23_clock_source_desc *cs = p; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return GET_VAL(cs, proto, bClockID) == id; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic bool validate_clock_selector(void *p, int id, int proto) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci union uac23_clock_selector_desc *cs = p; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return GET_VAL(cs, proto, bClockID) == id; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic bool validate_clock_multiplier(void *p, int id, int proto) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci union uac23_clock_multiplier_desc *cs = p; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return GET_VAL(cs, proto, bClockID) == id; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \ 7962306a36Sopenharmony_cistatic obj *name(struct snd_usb_audio *chip, int id, int proto) \ 8062306a36Sopenharmony_ci{ \ 8162306a36Sopenharmony_ci return find_uac_clock_desc(chip->ctrl_intf, id, validator, \ 8262306a36Sopenharmony_ci proto == UAC_VERSION_3 ? (type3) : (type2), \ 8362306a36Sopenharmony_ci proto); \ 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciDEFINE_FIND_HELPER(snd_usb_find_clock_source, 8762306a36Sopenharmony_ci union uac23_clock_source_desc, validate_clock_source, 8862306a36Sopenharmony_ci UAC2_CLOCK_SOURCE, UAC3_CLOCK_SOURCE); 8962306a36Sopenharmony_ciDEFINE_FIND_HELPER(snd_usb_find_clock_selector, 9062306a36Sopenharmony_ci union uac23_clock_selector_desc, validate_clock_selector, 9162306a36Sopenharmony_ci UAC2_CLOCK_SELECTOR, UAC3_CLOCK_SELECTOR); 9262306a36Sopenharmony_ciDEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, 9362306a36Sopenharmony_ci union uac23_clock_multiplier_desc, validate_clock_multiplier, 9462306a36Sopenharmony_ci UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci unsigned char buf; 9962306a36Sopenharmony_ci int ret; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 10262306a36Sopenharmony_ci UAC2_CS_CUR, 10362306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 10462306a36Sopenharmony_ci UAC2_CX_CLOCK_SELECTOR << 8, 10562306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (selector_id << 8), 10662306a36Sopenharmony_ci &buf, sizeof(buf)); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (ret < 0) 10962306a36Sopenharmony_ci return ret; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return buf; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, 11562306a36Sopenharmony_ci unsigned char pin) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int ret; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 12062306a36Sopenharmony_ci UAC2_CS_CUR, 12162306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 12262306a36Sopenharmony_ci UAC2_CX_CLOCK_SELECTOR << 8, 12362306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (selector_id << 8), 12462306a36Sopenharmony_ci &pin, sizeof(pin)); 12562306a36Sopenharmony_ci if (ret < 0) 12662306a36Sopenharmony_ci return ret; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (ret != sizeof(pin)) { 12962306a36Sopenharmony_ci usb_audio_err(chip, 13062306a36Sopenharmony_ci "setting selector (id %d) unexpected length %d\n", 13162306a36Sopenharmony_ci selector_id, ret); 13262306a36Sopenharmony_ci return -EINVAL; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ret = uac_clock_selector_get_val(chip, selector_id); 13662306a36Sopenharmony_ci if (ret < 0) 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (ret != pin) { 14062306a36Sopenharmony_ci usb_audio_err(chip, 14162306a36Sopenharmony_ci "setting selector (id %d) to %x failed (current: %d)\n", 14262306a36Sopenharmony_ci selector_id, pin, ret); 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, 15062306a36Sopenharmony_ci const struct audioformat *fmt, 15162306a36Sopenharmony_ci int source_id) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci bool ret = false; 15462306a36Sopenharmony_ci int count; 15562306a36Sopenharmony_ci unsigned char data; 15662306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 15762306a36Sopenharmony_ci union uac23_clock_source_desc *cs_desc; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); 16062306a36Sopenharmony_ci if (!cs_desc) 16162306a36Sopenharmony_ci return false; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (fmt->protocol == UAC_VERSION_2) { 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Assume the clock is valid if clock source supports only one 16662306a36Sopenharmony_ci * single sample rate, the terminal is connected directly to it 16762306a36Sopenharmony_ci * (there is no clock selector) and clock type is internal. 16862306a36Sopenharmony_ci * This is to deal with some Denon DJ controllers that always 16962306a36Sopenharmony_ci * reports that clock is invalid. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci if (fmt->nr_rates == 1 && 17262306a36Sopenharmony_ci (fmt->clock & 0xff) == cs_desc->v2.bClockID && 17362306a36Sopenharmony_ci (cs_desc->v2.bmAttributes & 0x3) != 17462306a36Sopenharmony_ci UAC_CLOCK_SOURCE_TYPE_EXT) 17562306a36Sopenharmony_ci return true; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * MOTU MicroBook IIc 18062306a36Sopenharmony_ci * Sample rate changes takes more than 2 seconds for this device. Clock 18162306a36Sopenharmony_ci * validity request returns false during that period. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci if (chip->usb_id == USB_ID(0x07fd, 0x0004)) { 18462306a36Sopenharmony_ci count = 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci while ((!ret) && (count < 50)) { 18762306a36Sopenharmony_ci int err; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci msleep(100); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 19262306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 19362306a36Sopenharmony_ci UAC2_CS_CONTROL_CLOCK_VALID << 8, 19462306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (source_id << 8), 19562306a36Sopenharmony_ci &data, sizeof(data)); 19662306a36Sopenharmony_ci if (err < 0) { 19762306a36Sopenharmony_ci dev_warn(&dev->dev, 19862306a36Sopenharmony_ci "%s(): cannot get clock validity for id %d\n", 19962306a36Sopenharmony_ci __func__, source_id); 20062306a36Sopenharmony_ci return false; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ret = !!data; 20462306a36Sopenharmony_ci count++; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return ret; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic bool uac_clock_source_is_valid(struct snd_usb_audio *chip, 21262306a36Sopenharmony_ci const struct audioformat *fmt, 21362306a36Sopenharmony_ci int source_id) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci int err; 21662306a36Sopenharmony_ci unsigned char data; 21762306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 21862306a36Sopenharmony_ci u32 bmControls; 21962306a36Sopenharmony_ci union uac23_clock_source_desc *cs_desc; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); 22262306a36Sopenharmony_ci if (!cs_desc) 22362306a36Sopenharmony_ci return false; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (fmt->protocol == UAC_VERSION_3) 22662306a36Sopenharmony_ci bmControls = le32_to_cpu(cs_desc->v3.bmControls); 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci bmControls = cs_desc->v2.bmControls; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* If a clock source can't tell us whether it's valid, we assume it is */ 23162306a36Sopenharmony_ci if (!uac_v2v3_control_is_readable(bmControls, 23262306a36Sopenharmony_ci UAC2_CS_CONTROL_CLOCK_VALID)) 23362306a36Sopenharmony_ci return true; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 23662306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 23762306a36Sopenharmony_ci UAC2_CS_CONTROL_CLOCK_VALID << 8, 23862306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (source_id << 8), 23962306a36Sopenharmony_ci &data, sizeof(data)); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (err < 0) { 24262306a36Sopenharmony_ci dev_warn(&dev->dev, 24362306a36Sopenharmony_ci "%s(): cannot get clock validity for id %d\n", 24462306a36Sopenharmony_ci __func__, source_id); 24562306a36Sopenharmony_ci return false; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (data) 24962306a36Sopenharmony_ci return true; 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci return uac_clock_source_is_valid_quirk(chip, fmt, source_id); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int __uac_clock_find_source(struct snd_usb_audio *chip, 25562306a36Sopenharmony_ci const struct audioformat *fmt, int entity_id, 25662306a36Sopenharmony_ci unsigned long *visited, bool validate) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci union uac23_clock_source_desc *source; 25962306a36Sopenharmony_ci union uac23_clock_selector_desc *selector; 26062306a36Sopenharmony_ci union uac23_clock_multiplier_desc *multiplier; 26162306a36Sopenharmony_ci int ret, i, cur, err, pins, clock_id; 26262306a36Sopenharmony_ci const u8 *sources; 26362306a36Sopenharmony_ci int proto = fmt->protocol; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci entity_id &= 0xff; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (test_and_set_bit(entity_id, visited)) { 26862306a36Sopenharmony_ci usb_audio_warn(chip, 26962306a36Sopenharmony_ci "%s(): recursive clock topology detected, id %d.\n", 27062306a36Sopenharmony_ci __func__, entity_id); 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* first, see if the ID we're looking at is a clock source already */ 27562306a36Sopenharmony_ci source = snd_usb_find_clock_source(chip, entity_id, proto); 27662306a36Sopenharmony_ci if (source) { 27762306a36Sopenharmony_ci entity_id = GET_VAL(source, proto, bClockID); 27862306a36Sopenharmony_ci if (validate && !uac_clock_source_is_valid(chip, fmt, 27962306a36Sopenharmony_ci entity_id)) { 28062306a36Sopenharmony_ci usb_audio_err(chip, 28162306a36Sopenharmony_ci "clock source %d is not valid, cannot use\n", 28262306a36Sopenharmony_ci entity_id); 28362306a36Sopenharmony_ci return -ENXIO; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci return entity_id; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci selector = snd_usb_find_clock_selector(chip, entity_id, proto); 28962306a36Sopenharmony_ci if (selector) { 29062306a36Sopenharmony_ci pins = GET_VAL(selector, proto, bNrInPins); 29162306a36Sopenharmony_ci clock_id = GET_VAL(selector, proto, bClockID); 29262306a36Sopenharmony_ci sources = GET_VAL(selector, proto, baCSourceID); 29362306a36Sopenharmony_ci cur = 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (pins == 1) { 29662306a36Sopenharmony_ci ret = 1; 29762306a36Sopenharmony_ci goto find_source; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* the entity ID we are looking at is a selector. 30162306a36Sopenharmony_ci * find out what it currently selects */ 30262306a36Sopenharmony_ci ret = uac_clock_selector_get_val(chip, clock_id); 30362306a36Sopenharmony_ci if (ret < 0) { 30462306a36Sopenharmony_ci if (!chip->autoclock) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci goto find_others; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Selector values are one-based */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (ret > pins || ret < 1) { 31262306a36Sopenharmony_ci usb_audio_err(chip, 31362306a36Sopenharmony_ci "%s(): selector reported illegal value, id %d, ret %d\n", 31462306a36Sopenharmony_ci __func__, clock_id, ret); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!chip->autoclock) 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci goto find_others; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci find_source: 32262306a36Sopenharmony_ci cur = ret; 32362306a36Sopenharmony_ci ret = __uac_clock_find_source(chip, fmt, 32462306a36Sopenharmony_ci sources[ret - 1], 32562306a36Sopenharmony_ci visited, validate); 32662306a36Sopenharmony_ci if (ret > 0) { 32762306a36Sopenharmony_ci /* Skip setting clock selector again for some devices */ 32862306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR) 32962306a36Sopenharmony_ci return ret; 33062306a36Sopenharmony_ci err = uac_clock_selector_set_val(chip, entity_id, cur); 33162306a36Sopenharmony_ci if (err < 0) { 33262306a36Sopenharmony_ci if (pins == 1) { 33362306a36Sopenharmony_ci usb_audio_dbg(chip, 33462306a36Sopenharmony_ci "%s(): selector returned an error, " 33562306a36Sopenharmony_ci "assuming a firmware bug, id %d, ret %d\n", 33662306a36Sopenharmony_ci __func__, clock_id, err); 33762306a36Sopenharmony_ci return ret; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci return err; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!validate || ret > 0 || !chip->autoclock) 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci find_others: 34762306a36Sopenharmony_ci /* The current clock source is invalid, try others. */ 34862306a36Sopenharmony_ci for (i = 1; i <= pins; i++) { 34962306a36Sopenharmony_ci if (i == cur) 35062306a36Sopenharmony_ci continue; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci ret = __uac_clock_find_source(chip, fmt, 35362306a36Sopenharmony_ci sources[i - 1], 35462306a36Sopenharmony_ci visited, true); 35562306a36Sopenharmony_ci if (ret < 0) 35662306a36Sopenharmony_ci continue; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci err = uac_clock_selector_set_val(chip, entity_id, i); 35962306a36Sopenharmony_ci if (err < 0) 36062306a36Sopenharmony_ci continue; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci usb_audio_info(chip, 36362306a36Sopenharmony_ci "found and selected valid clock source %d\n", 36462306a36Sopenharmony_ci ret); 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return -ENXIO; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* FIXME: multipliers only act as pass-thru element for now */ 37262306a36Sopenharmony_ci multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto); 37362306a36Sopenharmony_ci if (multiplier) 37462306a36Sopenharmony_ci return __uac_clock_find_source(chip, fmt, 37562306a36Sopenharmony_ci GET_VAL(multiplier, proto, bCSourceID), 37662306a36Sopenharmony_ci visited, validate); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return -EINVAL; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* 38262306a36Sopenharmony_ci * For all kinds of sample rate settings and other device queries, 38362306a36Sopenharmony_ci * the clock source (end-leaf) must be used. However, clock selectors, 38462306a36Sopenharmony_ci * clock multipliers and sample rate converters may be specified as 38562306a36Sopenharmony_ci * clock source input to terminal. This functions walks the clock path 38662306a36Sopenharmony_ci * to its end and tries to find the source. 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * The 'visited' bitfield is used internally to detect recursive loops. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * Returns the clock source UnitID (>=0) on success, or an error. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ciint snd_usb_clock_find_source(struct snd_usb_audio *chip, 39362306a36Sopenharmony_ci const struct audioformat *fmt, bool validate) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci DECLARE_BITMAP(visited, 256); 39662306a36Sopenharmony_ci memset(visited, 0, sizeof(visited)); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci switch (fmt->protocol) { 39962306a36Sopenharmony_ci case UAC_VERSION_2: 40062306a36Sopenharmony_ci case UAC_VERSION_3: 40162306a36Sopenharmony_ci return __uac_clock_find_source(chip, fmt, fmt->clock, visited, 40262306a36Sopenharmony_ci validate); 40362306a36Sopenharmony_ci default: 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int set_sample_rate_v1(struct snd_usb_audio *chip, 40962306a36Sopenharmony_ci const struct audioformat *fmt, int rate) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 41262306a36Sopenharmony_ci unsigned char data[3]; 41362306a36Sopenharmony_ci int err, crate; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* if endpoint doesn't have sampling rate control, bail out */ 41662306a36Sopenharmony_ci if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci data[0] = rate; 42062306a36Sopenharmony_ci data[1] = rate >> 8; 42162306a36Sopenharmony_ci data[2] = rate >> 16; 42262306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 42362306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 42462306a36Sopenharmony_ci UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 42562306a36Sopenharmony_ci fmt->endpoint, data, sizeof(data)); 42662306a36Sopenharmony_ci if (err < 0) { 42762306a36Sopenharmony_ci dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", 42862306a36Sopenharmony_ci fmt->iface, fmt->altsetting, rate, fmt->endpoint); 42962306a36Sopenharmony_ci return err; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* Don't check the sample rate for devices which we know don't 43362306a36Sopenharmony_ci * support reading */ 43462306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_GET_SAMPLE_RATE) 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci /* the firmware is likely buggy, don't repeat to fail too many times */ 43762306a36Sopenharmony_ci if (chip->sample_rate_read_error > 2) 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 44162306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 44262306a36Sopenharmony_ci UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 44362306a36Sopenharmony_ci fmt->endpoint, data, sizeof(data)); 44462306a36Sopenharmony_ci if (err < 0) { 44562306a36Sopenharmony_ci dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", 44662306a36Sopenharmony_ci fmt->iface, fmt->altsetting, fmt->endpoint); 44762306a36Sopenharmony_ci chip->sample_rate_read_error++; 44862306a36Sopenharmony_ci return 0; /* some devices don't support reading */ 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci crate = data[0] | (data[1] << 8) | (data[2] << 16); 45262306a36Sopenharmony_ci if (!crate) { 45362306a36Sopenharmony_ci dev_info(&dev->dev, "failed to read current rate; disabling the check\n"); 45462306a36Sopenharmony_ci chip->sample_rate_read_error = 3; /* three strikes, see above */ 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (crate != rate) { 45962306a36Sopenharmony_ci dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate); 46062306a36Sopenharmony_ci // runtime->rate = crate; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, 46762306a36Sopenharmony_ci int altsetting, int clock) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 47062306a36Sopenharmony_ci __le32 data; 47162306a36Sopenharmony_ci int err; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 47462306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 47562306a36Sopenharmony_ci UAC2_CS_CONTROL_SAM_FREQ << 8, 47662306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (clock << 8), 47762306a36Sopenharmony_ci &data, sizeof(data)); 47862306a36Sopenharmony_ci if (err < 0) { 47962306a36Sopenharmony_ci dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", 48062306a36Sopenharmony_ci iface, altsetting, err); 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return le32_to_cpu(data); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/* 48862306a36Sopenharmony_ci * Try to set the given sample rate: 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * Return 0 if the clock source is read-only, the actual rate on success, 49162306a36Sopenharmony_ci * or a negative error code. 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * This function gets called from format.c to validate each sample rate, too. 49462306a36Sopenharmony_ci * Hence no message is shown upon error 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ciint snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, 49762306a36Sopenharmony_ci const struct audioformat *fmt, 49862306a36Sopenharmony_ci int clock, int rate) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci bool writeable; 50162306a36Sopenharmony_ci u32 bmControls; 50262306a36Sopenharmony_ci __le32 data; 50362306a36Sopenharmony_ci int err; 50462306a36Sopenharmony_ci union uac23_clock_source_desc *cs_desc; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!cs_desc) 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (fmt->protocol == UAC_VERSION_3) 51262306a36Sopenharmony_ci bmControls = le32_to_cpu(cs_desc->v3.bmControls); 51362306a36Sopenharmony_ci else 51462306a36Sopenharmony_ci bmControls = cs_desc->v2.bmControls; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci writeable = uac_v2v3_control_is_writeable(bmControls, 51762306a36Sopenharmony_ci UAC2_CS_CONTROL_SAM_FREQ); 51862306a36Sopenharmony_ci if (!writeable) 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci data = cpu_to_le32(rate); 52262306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR, 52362306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 52462306a36Sopenharmony_ci UAC2_CS_CONTROL_SAM_FREQ << 8, 52562306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (clock << 8), 52662306a36Sopenharmony_ci &data, sizeof(data)); 52762306a36Sopenharmony_ci if (err < 0) 52862306a36Sopenharmony_ci return err; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int set_sample_rate_v2v3(struct snd_usb_audio *chip, 53462306a36Sopenharmony_ci const struct audioformat *fmt, int rate) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int cur_rate, prev_rate; 53762306a36Sopenharmony_ci int clock; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* First, try to find a valid clock. This may trigger 54062306a36Sopenharmony_ci * automatic clock selection if the current clock is not 54162306a36Sopenharmony_ci * valid. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci clock = snd_usb_clock_find_source(chip, fmt, true); 54462306a36Sopenharmony_ci if (clock < 0) { 54562306a36Sopenharmony_ci /* We did not find a valid clock, but that might be 54662306a36Sopenharmony_ci * because the current sample rate does not match an 54762306a36Sopenharmony_ci * external clock source. Try again without validation 54862306a36Sopenharmony_ci * and we will do another validation after setting the 54962306a36Sopenharmony_ci * rate. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci clock = snd_usb_clock_find_source(chip, fmt, false); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* Hardcoded sample rates */ 55462306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_IGNORE_CLOCK_SOURCE) 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (clock < 0) 55862306a36Sopenharmony_ci return clock; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); 56262306a36Sopenharmony_ci if (prev_rate == rate) 56362306a36Sopenharmony_ci goto validation; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate); 56662306a36Sopenharmony_ci if (cur_rate < 0) { 56762306a36Sopenharmony_ci usb_audio_err(chip, 56862306a36Sopenharmony_ci "%d:%d: cannot set freq %d (v2/v3): err %d\n", 56962306a36Sopenharmony_ci fmt->iface, fmt->altsetting, rate, cur_rate); 57062306a36Sopenharmony_ci return cur_rate; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!cur_rate) 57462306a36Sopenharmony_ci cur_rate = prev_rate; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (cur_rate != rate) { 57762306a36Sopenharmony_ci usb_audio_dbg(chip, 57862306a36Sopenharmony_ci "%d:%d: freq mismatch: req %d, clock runs @%d\n", 57962306a36Sopenharmony_ci fmt->iface, fmt->altsetting, rate, cur_rate); 58062306a36Sopenharmony_ci /* continue processing */ 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* FIXME - TEAC devices require the immediate interface setup */ 58462306a36Sopenharmony_ci if (USB_ID_VENDOR(chip->usb_id) == 0x0644) { 58562306a36Sopenharmony_ci bool cur_base_48k = (rate % 48000 == 0); 58662306a36Sopenharmony_ci bool prev_base_48k = (prev_rate % 48000 == 0); 58762306a36Sopenharmony_ci if (cur_base_48k != prev_base_48k) { 58862306a36Sopenharmony_ci usb_set_interface(chip->dev, fmt->iface, fmt->altsetting); 58962306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_IFACE_DELAY) 59062306a36Sopenharmony_ci msleep(50); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_civalidation: 59562306a36Sopenharmony_ci /* validate clock after rate change */ 59662306a36Sopenharmony_ci if (!uac_clock_source_is_valid(chip, fmt, clock)) 59762306a36Sopenharmony_ci return -ENXIO; 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciint snd_usb_init_sample_rate(struct snd_usb_audio *chip, 60262306a36Sopenharmony_ci const struct audioformat *fmt, int rate) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci usb_audio_dbg(chip, "%d:%d Set sample rate %d, clock %d\n", 60562306a36Sopenharmony_ci fmt->iface, fmt->altsetting, rate, fmt->clock); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci switch (fmt->protocol) { 60862306a36Sopenharmony_ci case UAC_VERSION_1: 60962306a36Sopenharmony_ci default: 61062306a36Sopenharmony_ci return set_sample_rate_v1(chip, fmt, rate); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci case UAC_VERSION_3: 61362306a36Sopenharmony_ci if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { 61462306a36Sopenharmony_ci if (rate != UAC3_BADD_SAMPLING_RATE) 61562306a36Sopenharmony_ci return -ENXIO; 61662306a36Sopenharmony_ci else 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci fallthrough; 62062306a36Sopenharmony_ci case UAC_VERSION_2: 62162306a36Sopenharmony_ci return set_sample_rate_v2v3(chip, fmt, rate); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 625