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> 2679f920fbSDaniel Mack 2779f920fbSDaniel Mack #include <sound/core.h> 2879f920fbSDaniel Mack #include <sound/info.h> 2979f920fbSDaniel Mack #include <sound/pcm.h> 3079f920fbSDaniel Mack 3179f920fbSDaniel Mack #include "usbaudio.h" 3279f920fbSDaniel Mack #include "card.h" 3379f920fbSDaniel Mack #include "helper.h" 34f22aa949SDaniel Mack #include "clock.h" 3579f920fbSDaniel Mack 3679f920fbSDaniel Mack static struct uac_clock_source_descriptor * 3779f920fbSDaniel Mack snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, 3879f920fbSDaniel Mack int clock_id) 3979f920fbSDaniel Mack { 4079f920fbSDaniel Mack struct uac_clock_source_descriptor *cs = NULL; 4179f920fbSDaniel Mack 4279f920fbSDaniel Mack while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, 4379f920fbSDaniel Mack ctrl_iface->extralen, 4479f920fbSDaniel Mack cs, UAC2_CLOCK_SOURCE))) { 4579f920fbSDaniel Mack if (cs->bClockID == clock_id) 4679f920fbSDaniel Mack return cs; 4779f920fbSDaniel Mack } 4879f920fbSDaniel Mack 4979f920fbSDaniel Mack return NULL; 5079f920fbSDaniel Mack } 5179f920fbSDaniel Mack 5279f920fbSDaniel Mack static struct uac_clock_selector_descriptor * 5379f920fbSDaniel Mack snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, 5479f920fbSDaniel Mack int clock_id) 5579f920fbSDaniel Mack { 5679f920fbSDaniel Mack struct uac_clock_selector_descriptor *cs = NULL; 5779f920fbSDaniel Mack 5879f920fbSDaniel Mack while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, 5979f920fbSDaniel Mack ctrl_iface->extralen, 6079f920fbSDaniel Mack cs, UAC2_CLOCK_SELECTOR))) { 6179f920fbSDaniel Mack if (cs->bClockID == clock_id) 6279f920fbSDaniel Mack return cs; 6379f920fbSDaniel Mack } 6479f920fbSDaniel Mack 6579f920fbSDaniel Mack return NULL; 6679f920fbSDaniel Mack } 6779f920fbSDaniel Mack 6879f920fbSDaniel Mack static struct uac_clock_multiplier_descriptor * 6979f920fbSDaniel Mack snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, 7079f920fbSDaniel Mack int clock_id) 7179f920fbSDaniel Mack { 7279f920fbSDaniel Mack struct uac_clock_multiplier_descriptor *cs = NULL; 7379f920fbSDaniel Mack 7479f920fbSDaniel Mack while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, 7579f920fbSDaniel Mack ctrl_iface->extralen, 7679f920fbSDaniel Mack cs, UAC2_CLOCK_MULTIPLIER))) { 7779f920fbSDaniel Mack if (cs->bClockID == clock_id) 7879f920fbSDaniel Mack return cs; 7979f920fbSDaniel Mack } 8079f920fbSDaniel Mack 8179f920fbSDaniel Mack return NULL; 8279f920fbSDaniel Mack } 8379f920fbSDaniel Mack 8479f920fbSDaniel Mack static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) 8579f920fbSDaniel Mack { 8679f920fbSDaniel Mack unsigned char buf; 8779f920fbSDaniel Mack int ret; 8879f920fbSDaniel Mack 8979f920fbSDaniel Mack ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 9079f920fbSDaniel Mack UAC2_CS_CUR, 9179f920fbSDaniel Mack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 9211bcbc44SDaniel Mack UAC2_CX_CLOCK_SELECTOR << 8, 9311bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (selector_id << 8), 9417d900c4SClemens Ladisch &buf, sizeof(buf)); 9579f920fbSDaniel Mack 9679f920fbSDaniel Mack if (ret < 0) 9779f920fbSDaniel Mack return ret; 9879f920fbSDaniel Mack 9979f920fbSDaniel Mack return buf; 10079f920fbSDaniel Mack } 10179f920fbSDaniel Mack 1028c55af3fSEldad Zack static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, 1038c55af3fSEldad Zack unsigned char pin) 1048c55af3fSEldad Zack { 1058c55af3fSEldad Zack int ret; 1068c55af3fSEldad Zack 1078c55af3fSEldad Zack ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 1088c55af3fSEldad Zack UAC2_CS_CUR, 1098c55af3fSEldad Zack USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 1108c55af3fSEldad Zack UAC2_CX_CLOCK_SELECTOR << 8, 1118c55af3fSEldad Zack snd_usb_ctrl_intf(chip) | (selector_id << 8), 1128c55af3fSEldad Zack &pin, sizeof(pin)); 1138c55af3fSEldad Zack if (ret < 0) 1148c55af3fSEldad Zack return ret; 1158c55af3fSEldad Zack 1168c55af3fSEldad Zack if (ret != sizeof(pin)) { 1178c55af3fSEldad Zack snd_printk(KERN_ERR 1188c55af3fSEldad Zack "usb-audio:%d: setting selector (id %d) unexpected length %d\n", 1198c55af3fSEldad Zack chip->dev->devnum, selector_id, ret); 1208c55af3fSEldad Zack return -EINVAL; 1218c55af3fSEldad Zack } 1228c55af3fSEldad Zack 1238c55af3fSEldad Zack ret = uac_clock_selector_get_val(chip, selector_id); 1248c55af3fSEldad Zack if (ret < 0) 1258c55af3fSEldad Zack return ret; 1268c55af3fSEldad Zack 1278c55af3fSEldad Zack if (ret != pin) { 1288c55af3fSEldad Zack snd_printk(KERN_ERR 1298c55af3fSEldad Zack "usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n", 1308c55af3fSEldad Zack chip->dev->devnum, selector_id, pin, ret); 1318c55af3fSEldad Zack return -EINVAL; 1328c55af3fSEldad Zack } 1338c55af3fSEldad Zack 1348c55af3fSEldad Zack return ret; 1358c55af3fSEldad Zack } 1368c55af3fSEldad Zack 13779f920fbSDaniel Mack static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) 13879f920fbSDaniel Mack { 13979f920fbSDaniel Mack int err; 14079f920fbSDaniel Mack unsigned char data; 14179f920fbSDaniel Mack struct usb_device *dev = chip->dev; 1423bc6fbc7SDaniel Mack struct uac_clock_source_descriptor *cs_desc = 1433bc6fbc7SDaniel Mack snd_usb_find_clock_source(chip->ctrl_intf, source_id); 1443bc6fbc7SDaniel Mack 1453bc6fbc7SDaniel Mack if (!cs_desc) 1463bc6fbc7SDaniel Mack return 0; 1473bc6fbc7SDaniel Mack 1483bc6fbc7SDaniel Mack /* If a clock source can't tell us whether it's valid, we assume it is */ 149aff252a8SDaniel Mack if (!uac2_control_is_readable(cs_desc->bmControls, 150aff252a8SDaniel Mack UAC2_CS_CONTROL_CLOCK_VALID - 1)) 1513bc6fbc7SDaniel Mack return 1; 15279f920fbSDaniel Mack 15379f920fbSDaniel Mack err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 15479f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 15511bcbc44SDaniel Mack UAC2_CS_CONTROL_CLOCK_VALID << 8, 15611bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (source_id << 8), 15717d900c4SClemens Ladisch &data, sizeof(data)); 15879f920fbSDaniel Mack 15979f920fbSDaniel Mack if (err < 0) { 16079f920fbSDaniel Mack snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", 16179f920fbSDaniel Mack __func__, source_id); 1623bc6fbc7SDaniel Mack return 0; 16379f920fbSDaniel Mack } 16479f920fbSDaniel Mack 16579f920fbSDaniel Mack return !!data; 16679f920fbSDaniel Mack } 16779f920fbSDaniel Mack 16879f920fbSDaniel Mack static int __uac_clock_find_source(struct snd_usb_audio *chip, 16906ffc1ebSEldad Zack int entity_id, unsigned long *visited, 17006ffc1ebSEldad Zack bool validate) 17179f920fbSDaniel Mack { 17279f920fbSDaniel Mack struct uac_clock_source_descriptor *source; 17379f920fbSDaniel Mack struct uac_clock_selector_descriptor *selector; 17479f920fbSDaniel Mack struct uac_clock_multiplier_descriptor *multiplier; 17579f920fbSDaniel Mack 17679f920fbSDaniel Mack entity_id &= 0xff; 17779f920fbSDaniel Mack 17879f920fbSDaniel Mack if (test_and_set_bit(entity_id, visited)) { 17979f920fbSDaniel Mack snd_printk(KERN_WARNING 18079f920fbSDaniel Mack "%s(): recursive clock topology detected, id %d.\n", 18179f920fbSDaniel Mack __func__, entity_id); 18279f920fbSDaniel Mack return -EINVAL; 18379f920fbSDaniel Mack } 18479f920fbSDaniel Mack 18579f920fbSDaniel Mack /* first, see if the ID we're looking for is a clock source already */ 1863d8d4dcfSDaniel Mack source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); 18706ffc1ebSEldad Zack if (source) { 18806ffc1ebSEldad Zack entity_id = source->bClockID; 18906ffc1ebSEldad Zack if (validate && !uac_clock_source_is_valid(chip, entity_id)) { 19006ffc1ebSEldad Zack snd_printk(KERN_ERR "usb-audio:%d: clock source %d is not valid, cannot use\n", 19106ffc1ebSEldad Zack chip->dev->devnum, entity_id); 19206ffc1ebSEldad Zack return -ENXIO; 19306ffc1ebSEldad Zack } 19406ffc1ebSEldad Zack return entity_id; 19506ffc1ebSEldad Zack } 19679f920fbSDaniel Mack 1973d8d4dcfSDaniel Mack selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); 19879f920fbSDaniel Mack if (selector) { 1998c55af3fSEldad Zack int ret, i, cur; 20079f920fbSDaniel Mack 20179f920fbSDaniel Mack /* the entity ID we are looking for is a selector. 20279f920fbSDaniel Mack * find out what it currently selects */ 20379f920fbSDaniel Mack ret = uac_clock_selector_get_val(chip, selector->bClockID); 20479f920fbSDaniel Mack if (ret < 0) 20579f920fbSDaniel Mack return ret; 20679f920fbSDaniel Mack 207157a57b6SDaniel Mack /* Selector values are one-based */ 208157a57b6SDaniel Mack 20979f920fbSDaniel Mack if (ret > selector->bNrInPins || ret < 1) { 21006ffc1ebSEldad Zack snd_printk(KERN_ERR 21179f920fbSDaniel Mack "%s(): selector reported illegal value, id %d, ret %d\n", 21279f920fbSDaniel Mack __func__, selector->bClockID, ret); 21379f920fbSDaniel Mack 21479f920fbSDaniel Mack return -EINVAL; 21579f920fbSDaniel Mack } 21679f920fbSDaniel Mack 2178c55af3fSEldad Zack cur = ret; 2188c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], 21906ffc1ebSEldad Zack visited, validate); 220ef02e29bSEldad Zack if (!validate || ret > 0 || !chip->autoclock) 2218c55af3fSEldad Zack return ret; 2228c55af3fSEldad Zack 2238c55af3fSEldad Zack /* The current clock source is invalid, try others. */ 2248c55af3fSEldad Zack for (i = 1; i <= selector->bNrInPins; i++) { 2258c55af3fSEldad Zack int err; 2268c55af3fSEldad Zack 2278c55af3fSEldad Zack if (i == cur) 2288c55af3fSEldad Zack continue; 2298c55af3fSEldad Zack 2308c55af3fSEldad Zack ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1], 2318c55af3fSEldad Zack visited, true); 2328c55af3fSEldad Zack if (ret < 0) 2338c55af3fSEldad Zack continue; 2348c55af3fSEldad Zack 2358c55af3fSEldad Zack err = uac_clock_selector_set_val(chip, entity_id, i); 2368c55af3fSEldad Zack if (err < 0) 2378c55af3fSEldad Zack continue; 2388c55af3fSEldad Zack 2398c55af3fSEldad Zack snd_printk(KERN_INFO 2408c55af3fSEldad Zack "usb-audio:%d: found and selected valid clock source %d\n", 2418c55af3fSEldad Zack chip->dev->devnum, ret); 2428c55af3fSEldad Zack return ret; 2438c55af3fSEldad Zack } 2448c55af3fSEldad Zack 2458c55af3fSEldad Zack return -ENXIO; 24679f920fbSDaniel Mack } 24779f920fbSDaniel Mack 24879f920fbSDaniel Mack /* FIXME: multipliers only act as pass-thru element for now */ 2493d8d4dcfSDaniel Mack multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); 25079f920fbSDaniel Mack if (multiplier) 2513d8d4dcfSDaniel Mack return __uac_clock_find_source(chip, multiplier->bCSourceID, 25206ffc1ebSEldad Zack visited, validate); 25379f920fbSDaniel Mack 25479f920fbSDaniel Mack return -EINVAL; 25579f920fbSDaniel Mack } 25679f920fbSDaniel Mack 257157a57b6SDaniel Mack /* 258157a57b6SDaniel Mack * For all kinds of sample rate settings and other device queries, 259157a57b6SDaniel Mack * the clock source (end-leaf) must be used. However, clock selectors, 260157a57b6SDaniel Mack * clock multipliers and sample rate converters may be specified as 261157a57b6SDaniel Mack * clock source input to terminal. This functions walks the clock path 262157a57b6SDaniel Mack * to its end and tries to find the source. 263157a57b6SDaniel Mack * 264157a57b6SDaniel Mack * The 'visited' bitfield is used internally to detect recursive loops. 265157a57b6SDaniel Mack * 266157a57b6SDaniel Mack * Returns the clock source UnitID (>=0) on success, or an error. 267157a57b6SDaniel Mack */ 26806ffc1ebSEldad Zack int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, 26906ffc1ebSEldad Zack bool validate) 27079f920fbSDaniel Mack { 27179f920fbSDaniel Mack DECLARE_BITMAP(visited, 256); 27279f920fbSDaniel Mack memset(visited, 0, sizeof(visited)); 27306ffc1ebSEldad Zack return __uac_clock_find_source(chip, entity_id, visited, validate); 27479f920fbSDaniel Mack } 27579f920fbSDaniel Mack 27679f920fbSDaniel Mack static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, 27779f920fbSDaniel Mack struct usb_host_interface *alts, 27879f920fbSDaniel Mack struct audioformat *fmt, int rate) 27979f920fbSDaniel Mack { 28079f920fbSDaniel Mack struct usb_device *dev = chip->dev; 28179f920fbSDaniel Mack unsigned int ep; 28279f920fbSDaniel Mack unsigned char data[3]; 28379f920fbSDaniel Mack int err, crate; 28479f920fbSDaniel Mack 28579f920fbSDaniel Mack ep = get_endpoint(alts, 0)->bEndpointAddress; 28679f920fbSDaniel Mack 28779f920fbSDaniel Mack /* if endpoint doesn't have sampling rate control, bail out */ 288d32d552eSClemens Ladisch if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) 28979f920fbSDaniel Mack return 0; 29079f920fbSDaniel Mack 29179f920fbSDaniel Mack data[0] = rate; 29279f920fbSDaniel Mack data[1] = rate >> 8; 29379f920fbSDaniel Mack data[2] = rate >> 16; 29479f920fbSDaniel Mack if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 29579f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 29679f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 29717d900c4SClemens Ladisch data, sizeof(data))) < 0) { 29879f920fbSDaniel Mack snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", 29979f920fbSDaniel Mack dev->devnum, iface, fmt->altsetting, rate, ep); 30079f920fbSDaniel Mack return err; 30179f920fbSDaniel Mack } 30279f920fbSDaniel Mack 30379f920fbSDaniel Mack if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 30479f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 30579f920fbSDaniel Mack UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, 30617d900c4SClemens Ladisch data, sizeof(data))) < 0) { 30779f920fbSDaniel Mack snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", 30879f920fbSDaniel Mack dev->devnum, iface, fmt->altsetting, ep); 30979f920fbSDaniel Mack return 0; /* some devices don't support reading */ 31079f920fbSDaniel Mack } 31179f920fbSDaniel Mack 31279f920fbSDaniel Mack crate = data[0] | (data[1] << 8) | (data[2] << 16); 31379f920fbSDaniel Mack if (crate != rate) { 31479f920fbSDaniel Mack snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); 31579f920fbSDaniel Mack // runtime->rate = crate; 31679f920fbSDaniel Mack } 31779f920fbSDaniel Mack 31879f920fbSDaniel Mack return 0; 31979f920fbSDaniel Mack } 32079f920fbSDaniel Mack 3217c517465STakashi Iwai static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, 3227c517465STakashi Iwai int altsetting, int clock) 3237c517465STakashi Iwai { 3247c517465STakashi Iwai struct usb_device *dev = chip->dev; 325f6a8bc70SEldad Zack __le32 data; 3267c517465STakashi Iwai int err; 3277c517465STakashi Iwai 3287c517465STakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, 3297c517465STakashi Iwai USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 3307c517465STakashi Iwai UAC2_CS_CONTROL_SAM_FREQ << 8, 3317c517465STakashi Iwai snd_usb_ctrl_intf(chip) | (clock << 8), 332f6a8bc70SEldad Zack &data, sizeof(data)); 3337c517465STakashi Iwai if (err < 0) { 334027bbc15SEldad Zack snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2): err %d\n", 335027bbc15SEldad Zack dev->devnum, iface, altsetting, err); 3367c517465STakashi Iwai return 0; 3377c517465STakashi Iwai } 3387c517465STakashi Iwai 339f6a8bc70SEldad Zack return le32_to_cpu(data); 3407c517465STakashi Iwai } 3417c517465STakashi Iwai 34279f920fbSDaniel Mack static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, 34379f920fbSDaniel Mack struct usb_host_interface *alts, 34479f920fbSDaniel Mack struct audioformat *fmt, int rate) 34579f920fbSDaniel Mack { 34679f920fbSDaniel Mack struct usb_device *dev = chip->dev; 347f6a8bc70SEldad Zack __le32 data; 348690a863fSTorstein Hegge int err, cur_rate, prev_rate; 3498c55af3fSEldad Zack int clock; 35079f920fbSDaniel Mack 3518c55af3fSEldad Zack clock = snd_usb_clock_find_source(chip, fmt->clock, true); 35279f920fbSDaniel Mack if (clock < 0) 35379f920fbSDaniel Mack return clock; 35479f920fbSDaniel Mack 3557c517465STakashi Iwai prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); 356690a863fSTorstein Hegge 357f6a8bc70SEldad Zack data = cpu_to_le32(rate); 35879f920fbSDaniel Mack if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 35979f920fbSDaniel Mack USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 36011bcbc44SDaniel Mack UAC2_CS_CONTROL_SAM_FREQ << 8, 36111bcbc44SDaniel Mack snd_usb_ctrl_intf(chip) | (clock << 8), 362f6a8bc70SEldad Zack &data, sizeof(data))) < 0) { 363027bbc15SEldad Zack snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n", 364027bbc15SEldad Zack dev->devnum, iface, fmt->altsetting, rate, err); 36579f920fbSDaniel Mack return err; 36679f920fbSDaniel Mack } 36779f920fbSDaniel Mack 3687c517465STakashi Iwai cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); 36979f920fbSDaniel Mack 370690a863fSTorstein Hegge if (cur_rate != rate) { 371690a863fSTorstein Hegge snd_printd(KERN_WARNING 372690a863fSTorstein Hegge "current rate %d is different from the runtime rate %d\n", 373690a863fSTorstein Hegge cur_rate, rate); 374690a863fSTorstein Hegge } 375690a863fSTorstein Hegge 376690a863fSTorstein Hegge /* Some devices doesn't respond to sample rate changes while the 377690a863fSTorstein Hegge * interface is active. */ 378690a863fSTorstein Hegge if (rate != prev_rate) { 379690a863fSTorstein Hegge usb_set_interface(dev, iface, 0); 380690a863fSTorstein Hegge usb_set_interface(dev, iface, fmt->altsetting); 381690a863fSTorstein Hegge } 38279f920fbSDaniel Mack 38379f920fbSDaniel Mack return 0; 38479f920fbSDaniel Mack } 38579f920fbSDaniel Mack 38679f920fbSDaniel Mack int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, 38779f920fbSDaniel Mack struct usb_host_interface *alts, 38879f920fbSDaniel Mack struct audioformat *fmt, int rate) 38979f920fbSDaniel Mack { 39079f920fbSDaniel Mack struct usb_interface_descriptor *altsd = get_iface_desc(alts); 39179f920fbSDaniel Mack 39279f920fbSDaniel Mack switch (altsd->bInterfaceProtocol) { 39379f920fbSDaniel Mack case UAC_VERSION_1: 394a2acad82SClemens Ladisch default: 39579f920fbSDaniel Mack return set_sample_rate_v1(chip, iface, alts, fmt, rate); 39679f920fbSDaniel Mack 39779f920fbSDaniel Mack case UAC_VERSION_2: 39879f920fbSDaniel Mack return set_sample_rate_v2(chip, iface, alts, fmt, rate); 39979f920fbSDaniel Mack } 40079f920fbSDaniel Mack } 40179f920fbSDaniel Mack 402