162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/init.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/usb.h>
862306a36Sopenharmony_ci#include <linux/usb/audio.h>
962306a36Sopenharmony_ci#include <linux/usb/midi.h>
1062306a36Sopenharmony_ci#include <linux/bits.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <sound/control.h>
1362306a36Sopenharmony_ci#include <sound/core.h>
1462306a36Sopenharmony_ci#include <sound/info.h>
1562306a36Sopenharmony_ci#include <sound/pcm.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "usbaudio.h"
1862306a36Sopenharmony_ci#include "card.h"
1962306a36Sopenharmony_ci#include "mixer.h"
2062306a36Sopenharmony_ci#include "mixer_quirks.h"
2162306a36Sopenharmony_ci#include "midi.h"
2262306a36Sopenharmony_ci#include "midi2.h"
2362306a36Sopenharmony_ci#include "quirks.h"
2462306a36Sopenharmony_ci#include "helper.h"
2562306a36Sopenharmony_ci#include "endpoint.h"
2662306a36Sopenharmony_ci#include "pcm.h"
2762306a36Sopenharmony_ci#include "clock.h"
2862306a36Sopenharmony_ci#include "stream.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * handle the quirks for the contained interfaces
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_cistatic int create_composite_quirk(struct snd_usb_audio *chip,
3462306a36Sopenharmony_ci				  struct usb_interface *iface,
3562306a36Sopenharmony_ci				  struct usb_driver *driver,
3662306a36Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk_comp)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
3962306a36Sopenharmony_ci	const struct snd_usb_audio_quirk *quirk;
4062306a36Sopenharmony_ci	int err;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
4362306a36Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
4462306a36Sopenharmony_ci		if (!iface)
4562306a36Sopenharmony_ci			continue;
4662306a36Sopenharmony_ci		if (quirk->ifnum != probed_ifnum &&
4762306a36Sopenharmony_ci		    usb_interface_claimed(iface))
4862306a36Sopenharmony_ci			continue;
4962306a36Sopenharmony_ci		err = snd_usb_create_quirk(chip, iface, driver, quirk);
5062306a36Sopenharmony_ci		if (err < 0)
5162306a36Sopenharmony_ci			return err;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
5562306a36Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
5662306a36Sopenharmony_ci		if (!iface)
5762306a36Sopenharmony_ci			continue;
5862306a36Sopenharmony_ci		if (quirk->ifnum != probed_ifnum &&
5962306a36Sopenharmony_ci		    !usb_interface_claimed(iface)) {
6062306a36Sopenharmony_ci			err = usb_driver_claim_interface(driver, iface,
6162306a36Sopenharmony_ci							 USB_AUDIO_IFACE_UNUSED);
6262306a36Sopenharmony_ci			if (err < 0)
6362306a36Sopenharmony_ci				return err;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int ignore_interface_quirk(struct snd_usb_audio *chip,
7162306a36Sopenharmony_ci				  struct usb_interface *iface,
7262306a36Sopenharmony_ci				  struct usb_driver *driver,
7362306a36Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int create_any_midi_quirk(struct snd_usb_audio *chip,
8062306a36Sopenharmony_ci				 struct usb_interface *intf,
8162306a36Sopenharmony_ci				 struct usb_driver *driver,
8262306a36Sopenharmony_ci				 const struct snd_usb_audio_quirk *quirk)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	return snd_usb_midi_v2_create(chip, intf, quirk, 0);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/*
8862306a36Sopenharmony_ci * create a stream for an interface with proper descriptors
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic int create_standard_audio_quirk(struct snd_usb_audio *chip,
9162306a36Sopenharmony_ci				       struct usb_interface *iface,
9262306a36Sopenharmony_ci				       struct usb_driver *driver,
9362306a36Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct usb_host_interface *alts;
9662306a36Sopenharmony_ci	struct usb_interface_descriptor *altsd;
9762306a36Sopenharmony_ci	int err;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	alts = &iface->altsetting[0];
10062306a36Sopenharmony_ci	altsd = get_iface_desc(alts);
10162306a36Sopenharmony_ci	err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
10262306a36Sopenharmony_ci	if (err < 0) {
10362306a36Sopenharmony_ci		usb_audio_err(chip, "cannot setup if %d: error %d\n",
10462306a36Sopenharmony_ci			   altsd->bInterfaceNumber, err);
10562306a36Sopenharmony_ci		return err;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	/* reset the current interface */
10862306a36Sopenharmony_ci	usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0);
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* create the audio stream and the corresponding endpoints from the fixed
11362306a36Sopenharmony_ci * audioformat object; this is used for quirks with the fixed EPs
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistatic int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
11662306a36Sopenharmony_ci					   struct audioformat *fp)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int stream, err;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	stream = (fp->endpoint & USB_DIR_IN) ?
12162306a36Sopenharmony_ci		SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	snd_usb_audioformat_set_sync_ep(chip, fp);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	err = snd_usb_add_audio_stream(chip, stream, fp);
12662306a36Sopenharmony_ci	if (err < 0)
12762306a36Sopenharmony_ci		return err;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	err = snd_usb_add_endpoint(chip, fp->endpoint,
13062306a36Sopenharmony_ci				   SND_USB_ENDPOINT_TYPE_DATA);
13162306a36Sopenharmony_ci	if (err < 0)
13262306a36Sopenharmony_ci		return err;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (fp->sync_ep) {
13562306a36Sopenharmony_ci		err = snd_usb_add_endpoint(chip, fp->sync_ep,
13662306a36Sopenharmony_ci					   fp->implicit_fb ?
13762306a36Sopenharmony_ci					   SND_USB_ENDPOINT_TYPE_DATA :
13862306a36Sopenharmony_ci					   SND_USB_ENDPOINT_TYPE_SYNC);
13962306a36Sopenharmony_ci		if (err < 0)
14062306a36Sopenharmony_ci			return err;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return 0;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/*
14762306a36Sopenharmony_ci * create a stream for an endpoint/altsetting without proper descriptors
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic int create_fixed_stream_quirk(struct snd_usb_audio *chip,
15062306a36Sopenharmony_ci				     struct usb_interface *iface,
15162306a36Sopenharmony_ci				     struct usb_driver *driver,
15262306a36Sopenharmony_ci				     const struct snd_usb_audio_quirk *quirk)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct audioformat *fp;
15562306a36Sopenharmony_ci	struct usb_host_interface *alts;
15662306a36Sopenharmony_ci	struct usb_interface_descriptor *altsd;
15762306a36Sopenharmony_ci	unsigned *rate_table = NULL;
15862306a36Sopenharmony_ci	int err;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
16162306a36Sopenharmony_ci	if (!fp)
16262306a36Sopenharmony_ci		return -ENOMEM;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	INIT_LIST_HEAD(&fp->list);
16562306a36Sopenharmony_ci	if (fp->nr_rates > MAX_NR_RATES) {
16662306a36Sopenharmony_ci		kfree(fp);
16762306a36Sopenharmony_ci		return -EINVAL;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci	if (fp->nr_rates > 0) {
17062306a36Sopenharmony_ci		rate_table = kmemdup(fp->rate_table,
17162306a36Sopenharmony_ci				     sizeof(int) * fp->nr_rates, GFP_KERNEL);
17262306a36Sopenharmony_ci		if (!rate_table) {
17362306a36Sopenharmony_ci			kfree(fp);
17462306a36Sopenharmony_ci			return -ENOMEM;
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		fp->rate_table = rate_table;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
18062306a36Sopenharmony_ci	    fp->altset_idx >= iface->num_altsetting) {
18162306a36Sopenharmony_ci		err = -EINVAL;
18262306a36Sopenharmony_ci		goto error;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	alts = &iface->altsetting[fp->altset_idx];
18562306a36Sopenharmony_ci	altsd = get_iface_desc(alts);
18662306a36Sopenharmony_ci	if (altsd->bNumEndpoints <= fp->ep_idx) {
18762306a36Sopenharmony_ci		err = -EINVAL;
18862306a36Sopenharmony_ci		goto error;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	fp->protocol = altsd->bInterfaceProtocol;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (fp->datainterval == 0)
19462306a36Sopenharmony_ci		fp->datainterval = snd_usb_parse_datainterval(chip, alts);
19562306a36Sopenharmony_ci	if (fp->maxpacksize == 0)
19662306a36Sopenharmony_ci		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, fp->ep_idx)->wMaxPacketSize);
19762306a36Sopenharmony_ci	if (!fp->fmt_type)
19862306a36Sopenharmony_ci		fp->fmt_type = UAC_FORMAT_TYPE_I;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	err = add_audio_stream_from_fixed_fmt(chip, fp);
20162306a36Sopenharmony_ci	if (err < 0)
20262306a36Sopenharmony_ci		goto error;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	usb_set_interface(chip->dev, fp->iface, 0);
20562306a36Sopenharmony_ci	snd_usb_init_pitch(chip, fp);
20662306a36Sopenharmony_ci	snd_usb_init_sample_rate(chip, fp, fp->rate_max);
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci error:
21062306a36Sopenharmony_ci	list_del(&fp->list); /* unlink for avoiding double-free */
21162306a36Sopenharmony_ci	kfree(fp);
21262306a36Sopenharmony_ci	kfree(rate_table);
21362306a36Sopenharmony_ci	return err;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int create_auto_pcm_quirk(struct snd_usb_audio *chip,
21762306a36Sopenharmony_ci				 struct usb_interface *iface,
21862306a36Sopenharmony_ci				 struct usb_driver *driver)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct usb_host_interface *alts;
22162306a36Sopenharmony_ci	struct usb_interface_descriptor *altsd;
22262306a36Sopenharmony_ci	struct usb_endpoint_descriptor *epd;
22362306a36Sopenharmony_ci	struct uac1_as_header_descriptor *ashd;
22462306a36Sopenharmony_ci	struct uac_format_type_i_discrete_descriptor *fmtd;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * Most Roland/Yamaha audio streaming interfaces have more or less
22862306a36Sopenharmony_ci	 * standard descriptors, but older devices might lack descriptors, and
22962306a36Sopenharmony_ci	 * future ones might change, so ensure that we fail silently if the
23062306a36Sopenharmony_ci	 * interface doesn't look exactly right.
23162306a36Sopenharmony_ci	 */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* must have a non-zero altsetting for streaming */
23462306a36Sopenharmony_ci	if (iface->num_altsetting < 2)
23562306a36Sopenharmony_ci		return -ENODEV;
23662306a36Sopenharmony_ci	alts = &iface->altsetting[1];
23762306a36Sopenharmony_ci	altsd = get_iface_desc(alts);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* must have an isochronous endpoint for streaming */
24062306a36Sopenharmony_ci	if (altsd->bNumEndpoints < 1)
24162306a36Sopenharmony_ci		return -ENODEV;
24262306a36Sopenharmony_ci	epd = get_endpoint(alts, 0);
24362306a36Sopenharmony_ci	if (!usb_endpoint_xfer_isoc(epd))
24462306a36Sopenharmony_ci		return -ENODEV;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* must have format descriptors */
24762306a36Sopenharmony_ci	ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
24862306a36Sopenharmony_ci				       UAC_AS_GENERAL);
24962306a36Sopenharmony_ci	fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
25062306a36Sopenharmony_ci				       UAC_FORMAT_TYPE);
25162306a36Sopenharmony_ci	if (!ashd || ashd->bLength < 7 ||
25262306a36Sopenharmony_ci	    !fmtd || fmtd->bLength < 8)
25362306a36Sopenharmony_ci		return -ENODEV;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return create_standard_audio_quirk(chip, iface, driver, NULL);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
25962306a36Sopenharmony_ci				    struct usb_interface *iface,
26062306a36Sopenharmony_ci				    struct usb_driver *driver,
26162306a36Sopenharmony_ci				    struct usb_host_interface *alts)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
26462306a36Sopenharmony_ci		.type = QUIRK_MIDI_YAMAHA
26562306a36Sopenharmony_ci	};
26662306a36Sopenharmony_ci	struct usb_midi_in_jack_descriptor *injd;
26762306a36Sopenharmony_ci	struct usb_midi_out_jack_descriptor *outjd;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* must have some valid jack descriptors */
27062306a36Sopenharmony_ci	injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
27162306a36Sopenharmony_ci				       NULL, USB_MS_MIDI_IN_JACK);
27262306a36Sopenharmony_ci	outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
27362306a36Sopenharmony_ci					NULL, USB_MS_MIDI_OUT_JACK);
27462306a36Sopenharmony_ci	if (!injd && !outjd)
27562306a36Sopenharmony_ci		return -ENODEV;
27662306a36Sopenharmony_ci	if ((injd && !snd_usb_validate_midi_desc(injd)) ||
27762306a36Sopenharmony_ci	    (outjd && !snd_usb_validate_midi_desc(outjd)))
27862306a36Sopenharmony_ci		return -ENODEV;
27962306a36Sopenharmony_ci	if (injd && (injd->bLength < 5 ||
28062306a36Sopenharmony_ci		     (injd->bJackType != USB_MS_EMBEDDED &&
28162306a36Sopenharmony_ci		      injd->bJackType != USB_MS_EXTERNAL)))
28262306a36Sopenharmony_ci		return -ENODEV;
28362306a36Sopenharmony_ci	if (outjd && (outjd->bLength < 6 ||
28462306a36Sopenharmony_ci		      (outjd->bJackType != USB_MS_EMBEDDED &&
28562306a36Sopenharmony_ci		       outjd->bJackType != USB_MS_EXTERNAL)))
28662306a36Sopenharmony_ci		return -ENODEV;
28762306a36Sopenharmony_ci	return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int create_roland_midi_quirk(struct snd_usb_audio *chip,
29162306a36Sopenharmony_ci				    struct usb_interface *iface,
29262306a36Sopenharmony_ci				    struct usb_driver *driver,
29362306a36Sopenharmony_ci				    struct usb_host_interface *alts)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	static const struct snd_usb_audio_quirk roland_midi_quirk = {
29662306a36Sopenharmony_ci		.type = QUIRK_MIDI_ROLAND
29762306a36Sopenharmony_ci	};
29862306a36Sopenharmony_ci	u8 *roland_desc = NULL;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* might have a vendor-specific descriptor <06 24 F1 02 ...> */
30162306a36Sopenharmony_ci	for (;;) {
30262306a36Sopenharmony_ci		roland_desc = snd_usb_find_csint_desc(alts->extra,
30362306a36Sopenharmony_ci						      alts->extralen,
30462306a36Sopenharmony_ci						      roland_desc, 0xf1);
30562306a36Sopenharmony_ci		if (!roland_desc)
30662306a36Sopenharmony_ci			return -ENODEV;
30762306a36Sopenharmony_ci		if (roland_desc[0] < 6 || roland_desc[3] != 2)
30862306a36Sopenharmony_ci			continue;
30962306a36Sopenharmony_ci		return create_any_midi_quirk(chip, iface, driver,
31062306a36Sopenharmony_ci					     &roland_midi_quirk);
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int create_std_midi_quirk(struct snd_usb_audio *chip,
31562306a36Sopenharmony_ci				 struct usb_interface *iface,
31662306a36Sopenharmony_ci				 struct usb_driver *driver,
31762306a36Sopenharmony_ci				 struct usb_host_interface *alts)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct usb_ms_header_descriptor *mshd;
32062306a36Sopenharmony_ci	struct usb_ms_endpoint_descriptor *msepd;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* must have the MIDIStreaming interface header descriptor*/
32362306a36Sopenharmony_ci	mshd = (struct usb_ms_header_descriptor *)alts->extra;
32462306a36Sopenharmony_ci	if (alts->extralen < 7 ||
32562306a36Sopenharmony_ci	    mshd->bLength < 7 ||
32662306a36Sopenharmony_ci	    mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
32762306a36Sopenharmony_ci	    mshd->bDescriptorSubtype != USB_MS_HEADER)
32862306a36Sopenharmony_ci		return -ENODEV;
32962306a36Sopenharmony_ci	/* must have the MIDIStreaming endpoint descriptor*/
33062306a36Sopenharmony_ci	msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
33162306a36Sopenharmony_ci	if (alts->endpoint[0].extralen < 4 ||
33262306a36Sopenharmony_ci	    msepd->bLength < 4 ||
33362306a36Sopenharmony_ci	    msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
33462306a36Sopenharmony_ci	    msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
33562306a36Sopenharmony_ci	    msepd->bNumEmbMIDIJack < 1 ||
33662306a36Sopenharmony_ci	    msepd->bNumEmbMIDIJack > 16)
33762306a36Sopenharmony_ci		return -ENODEV;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return create_any_midi_quirk(chip, iface, driver, NULL);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic int create_auto_midi_quirk(struct snd_usb_audio *chip,
34362306a36Sopenharmony_ci				  struct usb_interface *iface,
34462306a36Sopenharmony_ci				  struct usb_driver *driver)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct usb_host_interface *alts;
34762306a36Sopenharmony_ci	struct usb_interface_descriptor *altsd;
34862306a36Sopenharmony_ci	struct usb_endpoint_descriptor *epd;
34962306a36Sopenharmony_ci	int err;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	alts = &iface->altsetting[0];
35262306a36Sopenharmony_ci	altsd = get_iface_desc(alts);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* must have at least one bulk/interrupt endpoint for streaming */
35562306a36Sopenharmony_ci	if (altsd->bNumEndpoints < 1)
35662306a36Sopenharmony_ci		return -ENODEV;
35762306a36Sopenharmony_ci	epd = get_endpoint(alts, 0);
35862306a36Sopenharmony_ci	if (!usb_endpoint_xfer_bulk(epd) &&
35962306a36Sopenharmony_ci	    !usb_endpoint_xfer_int(epd))
36062306a36Sopenharmony_ci		return -ENODEV;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	switch (USB_ID_VENDOR(chip->usb_id)) {
36362306a36Sopenharmony_ci	case 0x0499: /* Yamaha */
36462306a36Sopenharmony_ci		err = create_yamaha_midi_quirk(chip, iface, driver, alts);
36562306a36Sopenharmony_ci		if (err != -ENODEV)
36662306a36Sopenharmony_ci			return err;
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci	case 0x0582: /* Roland */
36962306a36Sopenharmony_ci		err = create_roland_midi_quirk(chip, iface, driver, alts);
37062306a36Sopenharmony_ci		if (err != -ENODEV)
37162306a36Sopenharmony_ci			return err;
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return create_std_midi_quirk(chip, iface, driver, alts);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int create_autodetect_quirk(struct snd_usb_audio *chip,
37962306a36Sopenharmony_ci				   struct usb_interface *iface,
38062306a36Sopenharmony_ci				   struct usb_driver *driver,
38162306a36Sopenharmony_ci				   const struct snd_usb_audio_quirk *quirk)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	int err;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	err = create_auto_pcm_quirk(chip, iface, driver);
38662306a36Sopenharmony_ci	if (err == -ENODEV)
38762306a36Sopenharmony_ci		err = create_auto_midi_quirk(chip, iface, driver);
38862306a36Sopenharmony_ci	return err;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
39362306a36Sopenharmony_ci * The only way to detect the sample rate is by looking at wMaxPacketSize.
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistatic int create_uaxx_quirk(struct snd_usb_audio *chip,
39662306a36Sopenharmony_ci			     struct usb_interface *iface,
39762306a36Sopenharmony_ci			     struct usb_driver *driver,
39862306a36Sopenharmony_ci			     const struct snd_usb_audio_quirk *quirk)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	static const struct audioformat ua_format = {
40162306a36Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S24_3LE,
40262306a36Sopenharmony_ci		.channels = 2,
40362306a36Sopenharmony_ci		.fmt_type = UAC_FORMAT_TYPE_I,
40462306a36Sopenharmony_ci		.altsetting = 1,
40562306a36Sopenharmony_ci		.altset_idx = 1,
40662306a36Sopenharmony_ci		.rates = SNDRV_PCM_RATE_CONTINUOUS,
40762306a36Sopenharmony_ci	};
40862306a36Sopenharmony_ci	struct usb_host_interface *alts;
40962306a36Sopenharmony_ci	struct usb_interface_descriptor *altsd;
41062306a36Sopenharmony_ci	struct audioformat *fp;
41162306a36Sopenharmony_ci	int err;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* both PCM and MIDI interfaces have 2 or more altsettings */
41462306a36Sopenharmony_ci	if (iface->num_altsetting < 2)
41562306a36Sopenharmony_ci		return -ENXIO;
41662306a36Sopenharmony_ci	alts = &iface->altsetting[1];
41762306a36Sopenharmony_ci	altsd = get_iface_desc(alts);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (altsd->bNumEndpoints == 2) {
42062306a36Sopenharmony_ci		static const struct snd_usb_midi_endpoint_info ua700_ep = {
42162306a36Sopenharmony_ci			.out_cables = 0x0003,
42262306a36Sopenharmony_ci			.in_cables  = 0x0003
42362306a36Sopenharmony_ci		};
42462306a36Sopenharmony_ci		static const struct snd_usb_audio_quirk ua700_quirk = {
42562306a36Sopenharmony_ci			.type = QUIRK_MIDI_FIXED_ENDPOINT,
42662306a36Sopenharmony_ci			.data = &ua700_ep
42762306a36Sopenharmony_ci		};
42862306a36Sopenharmony_ci		static const struct snd_usb_midi_endpoint_info uaxx_ep = {
42962306a36Sopenharmony_ci			.out_cables = 0x0001,
43062306a36Sopenharmony_ci			.in_cables  = 0x0001
43162306a36Sopenharmony_ci		};
43262306a36Sopenharmony_ci		static const struct snd_usb_audio_quirk uaxx_quirk = {
43362306a36Sopenharmony_ci			.type = QUIRK_MIDI_FIXED_ENDPOINT,
43462306a36Sopenharmony_ci			.data = &uaxx_ep
43562306a36Sopenharmony_ci		};
43662306a36Sopenharmony_ci		const struct snd_usb_audio_quirk *quirk =
43762306a36Sopenharmony_ci			chip->usb_id == USB_ID(0x0582, 0x002b)
43862306a36Sopenharmony_ci			? &ua700_quirk : &uaxx_quirk;
43962306a36Sopenharmony_ci		return __snd_usbmidi_create(chip->card, iface,
44062306a36Sopenharmony_ci					    &chip->midi_list, quirk,
44162306a36Sopenharmony_ci					    chip->usb_id,
44262306a36Sopenharmony_ci					    &chip->num_rawmidis);
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (altsd->bNumEndpoints != 1)
44662306a36Sopenharmony_ci		return -ENXIO;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	fp = kmemdup(&ua_format, sizeof(*fp), GFP_KERNEL);
44962306a36Sopenharmony_ci	if (!fp)
45062306a36Sopenharmony_ci		return -ENOMEM;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	fp->iface = altsd->bInterfaceNumber;
45362306a36Sopenharmony_ci	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
45462306a36Sopenharmony_ci	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
45562306a36Sopenharmony_ci	fp->datainterval = 0;
45662306a36Sopenharmony_ci	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
45762306a36Sopenharmony_ci	INIT_LIST_HEAD(&fp->list);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	switch (fp->maxpacksize) {
46062306a36Sopenharmony_ci	case 0x120:
46162306a36Sopenharmony_ci		fp->rate_max = fp->rate_min = 44100;
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci	case 0x138:
46462306a36Sopenharmony_ci	case 0x140:
46562306a36Sopenharmony_ci		fp->rate_max = fp->rate_min = 48000;
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	case 0x258:
46862306a36Sopenharmony_ci	case 0x260:
46962306a36Sopenharmony_ci		fp->rate_max = fp->rate_min = 96000;
47062306a36Sopenharmony_ci		break;
47162306a36Sopenharmony_ci	default:
47262306a36Sopenharmony_ci		usb_audio_err(chip, "unknown sample rate\n");
47362306a36Sopenharmony_ci		kfree(fp);
47462306a36Sopenharmony_ci		return -ENXIO;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	err = add_audio_stream_from_fixed_fmt(chip, fp);
47862306a36Sopenharmony_ci	if (err < 0) {
47962306a36Sopenharmony_ci		list_del(&fp->list); /* unlink for avoiding double-free */
48062306a36Sopenharmony_ci		kfree(fp);
48162306a36Sopenharmony_ci		return err;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	usb_set_interface(chip->dev, fp->iface, 0);
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/*
48862306a36Sopenharmony_ci * Create a standard mixer for the specified interface.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic int create_standard_mixer_quirk(struct snd_usb_audio *chip,
49162306a36Sopenharmony_ci				       struct usb_interface *iface,
49262306a36Sopenharmony_ci				       struct usb_driver *driver,
49362306a36Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	if (quirk->ifnum < 0)
49662306a36Sopenharmony_ci		return 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return snd_usb_create_mixer(chip, quirk->ifnum);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * audio-interface quirks
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * returns zero if no standard audio/MIDI parsing is needed.
50562306a36Sopenharmony_ci * returns a positive value if standard audio/midi interfaces are parsed
50662306a36Sopenharmony_ci * after this.
50762306a36Sopenharmony_ci * returns a negative value at error.
50862306a36Sopenharmony_ci */
50962306a36Sopenharmony_ciint snd_usb_create_quirk(struct snd_usb_audio *chip,
51062306a36Sopenharmony_ci			 struct usb_interface *iface,
51162306a36Sopenharmony_ci			 struct usb_driver *driver,
51262306a36Sopenharmony_ci			 const struct snd_usb_audio_quirk *quirk)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	typedef int (*quirk_func_t)(struct snd_usb_audio *,
51562306a36Sopenharmony_ci				    struct usb_interface *,
51662306a36Sopenharmony_ci				    struct usb_driver *,
51762306a36Sopenharmony_ci				    const struct snd_usb_audio_quirk *);
51862306a36Sopenharmony_ci	static const quirk_func_t quirk_funcs[] = {
51962306a36Sopenharmony_ci		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
52062306a36Sopenharmony_ci		[QUIRK_COMPOSITE] = create_composite_quirk,
52162306a36Sopenharmony_ci		[QUIRK_AUTODETECT] = create_autodetect_quirk,
52262306a36Sopenharmony_ci		[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
52362306a36Sopenharmony_ci		[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
52462306a36Sopenharmony_ci		[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
52562306a36Sopenharmony_ci		[QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
52662306a36Sopenharmony_ci		[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
52762306a36Sopenharmony_ci		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
52862306a36Sopenharmony_ci		[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
52962306a36Sopenharmony_ci		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
53062306a36Sopenharmony_ci		[QUIRK_MIDI_CME] = create_any_midi_quirk,
53162306a36Sopenharmony_ci		[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
53262306a36Sopenharmony_ci		[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
53362306a36Sopenharmony_ci		[QUIRK_MIDI_CH345] = create_any_midi_quirk,
53462306a36Sopenharmony_ci		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
53562306a36Sopenharmony_ci		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
53662306a36Sopenharmony_ci		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
53762306a36Sopenharmony_ci		[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
53862306a36Sopenharmony_ci	};
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (quirk->type < QUIRK_TYPE_COUNT) {
54162306a36Sopenharmony_ci		return quirk_funcs[quirk->type](chip, iface, driver, quirk);
54262306a36Sopenharmony_ci	} else {
54362306a36Sopenharmony_ci		usb_audio_err(chip, "invalid quirk type %d\n", quirk->type);
54462306a36Sopenharmony_ci		return -ENXIO;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci/*
54962306a36Sopenharmony_ci * boot quirks
55062306a36Sopenharmony_ci */
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci#define EXTIGY_FIRMWARE_SIZE_OLD 794
55362306a36Sopenharmony_ci#define EXTIGY_FIRMWARE_SIZE_NEW 483
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct usb_host_config *config = dev->actconfig;
55862306a36Sopenharmony_ci	int err;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
56162306a36Sopenharmony_ci	    le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
56262306a36Sopenharmony_ci		dev_dbg(&dev->dev, "sending Extigy boot sequence...\n");
56362306a36Sopenharmony_ci		/* Send message to force it to reconnect with full interface. */
56462306a36Sopenharmony_ci		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
56562306a36Sopenharmony_ci				      0x10, 0x43, 0x0001, 0x000a, NULL, 0);
56662306a36Sopenharmony_ci		if (err < 0)
56762306a36Sopenharmony_ci			dev_dbg(&dev->dev, "error sending boot message: %d\n", err);
56862306a36Sopenharmony_ci		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
56962306a36Sopenharmony_ci				&dev->descriptor, sizeof(dev->descriptor));
57062306a36Sopenharmony_ci		config = dev->actconfig;
57162306a36Sopenharmony_ci		if (err < 0)
57262306a36Sopenharmony_ci			dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
57362306a36Sopenharmony_ci		err = usb_reset_configuration(dev);
57462306a36Sopenharmony_ci		if (err < 0)
57562306a36Sopenharmony_ci			dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
57662306a36Sopenharmony_ci		dev_dbg(&dev->dev, "extigy_boot: new boot length = %d\n",
57762306a36Sopenharmony_ci			    le16_to_cpu(get_cfg_desc(config)->wTotalLength));
57862306a36Sopenharmony_ci		return -ENODEV; /* quit this anyway */
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	u8 buf = 1;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
58862306a36Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
58962306a36Sopenharmony_ci			0, 0, &buf, 1);
59062306a36Sopenharmony_ci	if (buf == 0) {
59162306a36Sopenharmony_ci		snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
59262306a36Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
59362306a36Sopenharmony_ci				1, 2000, NULL, 0);
59462306a36Sopenharmony_ci		return -ENODEV;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	return 0;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	int err;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (dev->actconfig->desc.bConfigurationValue == 1) {
60462306a36Sopenharmony_ci		dev_info(&dev->dev,
60562306a36Sopenharmony_ci			   "Fast Track Pro switching to config #2\n");
60662306a36Sopenharmony_ci		/* This function has to be available by the usb core module.
60762306a36Sopenharmony_ci		 * if it is not avialable the boot quirk has to be left out
60862306a36Sopenharmony_ci		 * and the configuration has to be set by udev or hotplug
60962306a36Sopenharmony_ci		 * rules
61062306a36Sopenharmony_ci		 */
61162306a36Sopenharmony_ci		err = usb_driver_set_configuration(dev, 2);
61262306a36Sopenharmony_ci		if (err < 0)
61362306a36Sopenharmony_ci			dev_dbg(&dev->dev,
61462306a36Sopenharmony_ci				"error usb_driver_set_configuration: %d\n",
61562306a36Sopenharmony_ci				err);
61662306a36Sopenharmony_ci		/* Always return an error, so that we stop creating a device
61762306a36Sopenharmony_ci		   that will just be destroyed and recreated with a new
61862306a36Sopenharmony_ci		   configuration */
61962306a36Sopenharmony_ci		return -ENODEV;
62062306a36Sopenharmony_ci	} else
62162306a36Sopenharmony_ci		dev_info(&dev->dev, "Fast Track Pro config OK\n");
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/*
62762306a36Sopenharmony_ci * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
62862306a36Sopenharmony_ci * documented in the device's data sheet.
62962306a36Sopenharmony_ci */
63062306a36Sopenharmony_cistatic int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	u8 buf[4];
63362306a36Sopenharmony_ci	buf[0] = 0x20;
63462306a36Sopenharmony_ci	buf[1] = value & 0xff;
63562306a36Sopenharmony_ci	buf[2] = (value >> 8) & 0xff;
63662306a36Sopenharmony_ci	buf[3] = reg;
63762306a36Sopenharmony_ci	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
63862306a36Sopenharmony_ci			       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
63962306a36Sopenharmony_ci			       0, 0, &buf, 4);
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic int snd_usb_cm106_boot_quirk(struct usb_device *dev)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	/*
64562306a36Sopenharmony_ci	 * Enable line-out driver mode, set headphone source to front
64662306a36Sopenharmony_ci	 * channels, enable stereo mic.
64762306a36Sopenharmony_ci	 */
64862306a36Sopenharmony_ci	return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci/*
65262306a36Sopenharmony_ci * CM6206 registers from the CM6206 datasheet rev 2.1
65362306a36Sopenharmony_ci */
65462306a36Sopenharmony_ci#define CM6206_REG0_DMA_MASTER BIT(15)
65562306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_RATE_48K (2 << 12)
65662306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_RATE_96K (7 << 12)
65762306a36Sopenharmony_ci/* Bit 4 thru 11 is the S/PDIF category code */
65862306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_CAT_CODE_GENERAL (0 << 4)
65962306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_EMPHASIS_CD BIT(3)
66062306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_COPYRIGHT_NA BIT(2)
66162306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_NON_AUDIO BIT(1)
66262306a36Sopenharmony_ci#define CM6206_REG0_SPDIFO_PRO_FORMAT BIT(0)
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci#define CM6206_REG1_TEST_SEL_CLK BIT(14)
66562306a36Sopenharmony_ci#define CM6206_REG1_PLLBIN_EN BIT(13)
66662306a36Sopenharmony_ci#define CM6206_REG1_SOFT_MUTE_EN BIT(12)
66762306a36Sopenharmony_ci#define CM6206_REG1_GPIO4_OUT BIT(11)
66862306a36Sopenharmony_ci#define CM6206_REG1_GPIO4_OE BIT(10)
66962306a36Sopenharmony_ci#define CM6206_REG1_GPIO3_OUT BIT(9)
67062306a36Sopenharmony_ci#define CM6206_REG1_GPIO3_OE BIT(8)
67162306a36Sopenharmony_ci#define CM6206_REG1_GPIO2_OUT BIT(7)
67262306a36Sopenharmony_ci#define CM6206_REG1_GPIO2_OE BIT(6)
67362306a36Sopenharmony_ci#define CM6206_REG1_GPIO1_OUT BIT(5)
67462306a36Sopenharmony_ci#define CM6206_REG1_GPIO1_OE BIT(4)
67562306a36Sopenharmony_ci#define CM6206_REG1_SPDIFO_INVALID BIT(3)
67662306a36Sopenharmony_ci#define CM6206_REG1_SPDIF_LOOP_EN BIT(2)
67762306a36Sopenharmony_ci#define CM6206_REG1_SPDIFO_DIS BIT(1)
67862306a36Sopenharmony_ci#define CM6206_REG1_SPDIFI_MIX BIT(0)
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci#define CM6206_REG2_DRIVER_ON BIT(15)
68162306a36Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_SIDE_CHANNELS (0 << 13)
68262306a36Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_SURROUND_CHANNELS (1 << 13)
68362306a36Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_CENTER_SUBW (2 << 13)
68462306a36Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_FRONT_CHANNELS (3 << 13)
68562306a36Sopenharmony_ci#define CM6206_REG2_MUTE_HEADPHONE_RIGHT BIT(12)
68662306a36Sopenharmony_ci#define CM6206_REG2_MUTE_HEADPHONE_LEFT BIT(11)
68762306a36Sopenharmony_ci#define CM6206_REG2_MUTE_REAR_SURROUND_RIGHT BIT(10)
68862306a36Sopenharmony_ci#define CM6206_REG2_MUTE_REAR_SURROUND_LEFT BIT(9)
68962306a36Sopenharmony_ci#define CM6206_REG2_MUTE_SIDE_SURROUND_RIGHT BIT(8)
69062306a36Sopenharmony_ci#define CM6206_REG2_MUTE_SIDE_SURROUND_LEFT BIT(7)
69162306a36Sopenharmony_ci#define CM6206_REG2_MUTE_SUBWOOFER BIT(6)
69262306a36Sopenharmony_ci#define CM6206_REG2_MUTE_CENTER BIT(5)
69362306a36Sopenharmony_ci#define CM6206_REG2_MUTE_RIGHT_FRONT BIT(3)
69462306a36Sopenharmony_ci#define CM6206_REG2_MUTE_LEFT_FRONT BIT(3)
69562306a36Sopenharmony_ci#define CM6206_REG2_EN_BTL BIT(2)
69662306a36Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_1_5_MHZ (0)
69762306a36Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_3_MHZ (1)
69862306a36Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_6_MHZ (2)
69962306a36Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_12_MHZ (3)
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci/* Bit 11..13 sets the sensitivity to FLY tuner volume control VP/VD signal */
70262306a36Sopenharmony_ci#define CM6206_REG3_FLYSPEED_DEFAULT (2 << 11)
70362306a36Sopenharmony_ci#define CM6206_REG3_VRAP25EN BIT(10)
70462306a36Sopenharmony_ci#define CM6206_REG3_MSEL1 BIT(9)
70562306a36Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_44_1K BIT(0 << 7)
70662306a36Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_48K BIT(2 << 7)
70762306a36Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_32K BIT(3 << 7)
70862306a36Sopenharmony_ci#define CM6206_REG3_PINSEL BIT(6)
70962306a36Sopenharmony_ci#define CM6206_REG3_FOE BIT(5)
71062306a36Sopenharmony_ci#define CM6206_REG3_ROE BIT(4)
71162306a36Sopenharmony_ci#define CM6206_REG3_CBOE BIT(3)
71262306a36Sopenharmony_ci#define CM6206_REG3_LOSE BIT(2)
71362306a36Sopenharmony_ci#define CM6206_REG3_HPOE BIT(1)
71462306a36Sopenharmony_ci#define CM6206_REG3_SPDIFI_CANREC BIT(0)
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci#define CM6206_REG5_DA_RSTN BIT(13)
71762306a36Sopenharmony_ci#define CM6206_REG5_AD_RSTN BIT(12)
71862306a36Sopenharmony_ci#define CM6206_REG5_SPDIFO_AD2SPDO BIT(12)
71962306a36Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_FRONT (0 << 9)
72062306a36Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_SIDE_SUR (1 << 9)
72162306a36Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_CEN_LFE (2 << 9)
72262306a36Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_REAR_SUR (3 << 9)
72362306a36Sopenharmony_ci#define CM6206_REG5_CODECM BIT(8)
72462306a36Sopenharmony_ci#define CM6206_REG5_EN_HPF BIT(7)
72562306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA4 BIT(6)
72662306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA3 BIT(5)
72762306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA2 BIT(4)
72862306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA1 BIT(3)
72962306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_NORMAL 0
73062306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_FRONT 4
73162306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_S_SURROUND 5
73262306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_CEN_LFE 6
73362306a36Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_R_SURROUND 7
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	int err  = 0, reg;
73862306a36Sopenharmony_ci	int val[] = {
73962306a36Sopenharmony_ci		/*
74062306a36Sopenharmony_ci		 * Values here are chosen based on sniffing USB traffic
74162306a36Sopenharmony_ci		 * under Windows.
74262306a36Sopenharmony_ci		 *
74362306a36Sopenharmony_ci		 * REG0: DAC is master, sample rate 48kHz, no copyright
74462306a36Sopenharmony_ci		 */
74562306a36Sopenharmony_ci		CM6206_REG0_SPDIFO_RATE_48K |
74662306a36Sopenharmony_ci		CM6206_REG0_SPDIFO_COPYRIGHT_NA,
74762306a36Sopenharmony_ci		/*
74862306a36Sopenharmony_ci		 * REG1: PLL binary search enable, soft mute enable.
74962306a36Sopenharmony_ci		 */
75062306a36Sopenharmony_ci		CM6206_REG1_PLLBIN_EN |
75162306a36Sopenharmony_ci		CM6206_REG1_SOFT_MUTE_EN,
75262306a36Sopenharmony_ci		/*
75362306a36Sopenharmony_ci		 * REG2: enable output drivers,
75462306a36Sopenharmony_ci		 * select front channels to the headphone output,
75562306a36Sopenharmony_ci		 * then mute the headphone channels, run the MCU
75662306a36Sopenharmony_ci		 * at 1.5 MHz.
75762306a36Sopenharmony_ci		 */
75862306a36Sopenharmony_ci		CM6206_REG2_DRIVER_ON |
75962306a36Sopenharmony_ci		CM6206_REG2_HEADP_SEL_FRONT_CHANNELS |
76062306a36Sopenharmony_ci		CM6206_REG2_MUTE_HEADPHONE_RIGHT |
76162306a36Sopenharmony_ci		CM6206_REG2_MUTE_HEADPHONE_LEFT,
76262306a36Sopenharmony_ci		/*
76362306a36Sopenharmony_ci		 * REG3: default flyspeed, set 2.5V mic bias
76462306a36Sopenharmony_ci		 * enable all line out ports and enable SPDIF
76562306a36Sopenharmony_ci		 */
76662306a36Sopenharmony_ci		CM6206_REG3_FLYSPEED_DEFAULT |
76762306a36Sopenharmony_ci		CM6206_REG3_VRAP25EN |
76862306a36Sopenharmony_ci		CM6206_REG3_FOE |
76962306a36Sopenharmony_ci		CM6206_REG3_ROE |
77062306a36Sopenharmony_ci		CM6206_REG3_CBOE |
77162306a36Sopenharmony_ci		CM6206_REG3_LOSE |
77262306a36Sopenharmony_ci		CM6206_REG3_HPOE |
77362306a36Sopenharmony_ci		CM6206_REG3_SPDIFI_CANREC,
77462306a36Sopenharmony_ci		/* REG4 is just a bunch of GPIO lines */
77562306a36Sopenharmony_ci		0x0000,
77662306a36Sopenharmony_ci		/* REG5: de-assert AD/DA reset signals */
77762306a36Sopenharmony_ci		CM6206_REG5_DA_RSTN |
77862306a36Sopenharmony_ci		CM6206_REG5_AD_RSTN };
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
78162306a36Sopenharmony_ci		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
78262306a36Sopenharmony_ci		if (err < 0)
78362306a36Sopenharmony_ci			return err;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return err;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci/* quirk for Plantronics GameCom 780 with CM6302 chip */
79062306a36Sopenharmony_cistatic int snd_usb_gamecon780_boot_quirk(struct usb_device *dev)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	/* set the initial volume and don't change; other values are either
79362306a36Sopenharmony_ci	 * too loud or silent due to firmware bug (bko#65251)
79462306a36Sopenharmony_ci	 */
79562306a36Sopenharmony_ci	u8 buf[2] = { 0x74, 0xe3 };
79662306a36Sopenharmony_ci	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
79762306a36Sopenharmony_ci			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
79862306a36Sopenharmony_ci			UAC_FU_VOLUME << 8, 9 << 8, buf, 2);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci/*
80262306a36Sopenharmony_ci * Novation Twitch DJ controller
80362306a36Sopenharmony_ci * Focusrite Novation Saffire 6 USB audio card
80462306a36Sopenharmony_ci */
80562306a36Sopenharmony_cistatic int snd_usb_novation_boot_quirk(struct usb_device *dev)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	/* preemptively set up the device because otherwise the
80862306a36Sopenharmony_ci	 * raw MIDI endpoints are not active */
80962306a36Sopenharmony_ci	usb_set_interface(dev, 0, 1);
81062306a36Sopenharmony_ci	return 0;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci/*
81462306a36Sopenharmony_ci * This call will put the synth in "USB send" mode, i.e it will send MIDI
81562306a36Sopenharmony_ci * messages through USB (this is disabled at startup). The synth will
81662306a36Sopenharmony_ci * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
81762306a36Sopenharmony_ci * sign on its LCD. Values here are chosen based on sniffing USB traffic
81862306a36Sopenharmony_ci * under Windows.
81962306a36Sopenharmony_ci */
82062306a36Sopenharmony_cistatic int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	int err, actual_length;
82362306a36Sopenharmony_ci	/* "midi send" enable */
82462306a36Sopenharmony_ci	static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
82562306a36Sopenharmony_ci	void *buf;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x05)))
82862306a36Sopenharmony_ci		return -EINVAL;
82962306a36Sopenharmony_ci	buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
83062306a36Sopenharmony_ci	if (!buf)
83162306a36Sopenharmony_ci		return -ENOMEM;
83262306a36Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
83362306a36Sopenharmony_ci			ARRAY_SIZE(seq), &actual_length, 1000);
83462306a36Sopenharmony_ci	kfree(buf);
83562306a36Sopenharmony_ci	if (err < 0)
83662306a36Sopenharmony_ci		return err;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci/*
84262306a36Sopenharmony_ci * Some sound cards from Native Instruments are in fact compliant to the USB
84362306a36Sopenharmony_ci * audio standard of version 2 and other approved USB standards, even though
84462306a36Sopenharmony_ci * they come up as vendor-specific device when first connected.
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * However, they can be told to come up with a new set of descriptors
84762306a36Sopenharmony_ci * upon their next enumeration, and the interfaces announced by the new
84862306a36Sopenharmony_ci * descriptors will then be handled by the kernel's class drivers. As the
84962306a36Sopenharmony_ci * product ID will also change, no further checks are required.
85062306a36Sopenharmony_ci */
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	int ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
85762306a36Sopenharmony_ci				  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
85862306a36Sopenharmony_ci				  1, 0, NULL, 0, 1000);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (ret < 0)
86162306a36Sopenharmony_ci		return ret;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	usb_reset_device(dev);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* return -EAGAIN, so the creation of an audio interface for this
86662306a36Sopenharmony_ci	 * temporary device is aborted. The device will reconnect with a
86762306a36Sopenharmony_ci	 * new product ID */
86862306a36Sopenharmony_ci	return -EAGAIN;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic void mbox2_setup_48_24_magic(struct usb_device *dev)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	u8 srate[3];
87462306a36Sopenharmony_ci	u8 temp[12];
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* Choose 48000Hz permanently */
87762306a36Sopenharmony_ci	srate[0] = 0x80;
87862306a36Sopenharmony_ci	srate[1] = 0xbb;
87962306a36Sopenharmony_ci	srate[2] = 0x00;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* Send the magic! */
88262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
88362306a36Sopenharmony_ci		0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003);
88462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
88562306a36Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003);
88662306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
88762306a36Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003);
88862306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
88962306a36Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003);
89062306a36Sopenharmony_ci	return;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci/* Digidesign Mbox 2 needs to load firmware onboard
89462306a36Sopenharmony_ci * and driver must wait a few seconds for initialisation.
89562306a36Sopenharmony_ci */
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci#define MBOX2_FIRMWARE_SIZE    646
89862306a36Sopenharmony_ci#define MBOX2_BOOT_LOADING     0x01 /* Hard coded into the device */
89962306a36Sopenharmony_ci#define MBOX2_BOOT_READY       0x02 /* Hard coded into the device */
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct usb_host_config *config = dev->actconfig;
90462306a36Sopenharmony_ci	int err;
90562306a36Sopenharmony_ci	u8 bootresponse[0x12];
90662306a36Sopenharmony_ci	int fwsize;
90762306a36Sopenharmony_ci	int count;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (fwsize != MBOX2_FIRMWARE_SIZE) {
91262306a36Sopenharmony_ci		dev_err(&dev->dev, "Invalid firmware size=%d.\n", fwsize);
91362306a36Sopenharmony_ci		return -ENODEV;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	dev_dbg(&dev->dev, "Sending Digidesign Mbox 2 boot sequence...\n");
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	count = 0;
91962306a36Sopenharmony_ci	bootresponse[0] = MBOX2_BOOT_LOADING;
92062306a36Sopenharmony_ci	while ((bootresponse[0] == MBOX2_BOOT_LOADING) && (count < 10)) {
92162306a36Sopenharmony_ci		msleep(500); /* 0.5 second delay */
92262306a36Sopenharmony_ci		snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
92362306a36Sopenharmony_ci			/* Control magic - load onboard firmware */
92462306a36Sopenharmony_ci			0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012);
92562306a36Sopenharmony_ci		if (bootresponse[0] == MBOX2_BOOT_READY)
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci		dev_dbg(&dev->dev, "device not ready, resending boot sequence...\n");
92862306a36Sopenharmony_ci		count++;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (bootresponse[0] != MBOX2_BOOT_READY) {
93262306a36Sopenharmony_ci		dev_err(&dev->dev, "Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
93362306a36Sopenharmony_ci		return -ENODEV;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	dev_dbg(&dev->dev, "device initialised!\n");
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
93962306a36Sopenharmony_ci		&dev->descriptor, sizeof(dev->descriptor));
94062306a36Sopenharmony_ci	config = dev->actconfig;
94162306a36Sopenharmony_ci	if (err < 0)
94262306a36Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	err = usb_reset_configuration(dev);
94562306a36Sopenharmony_ci	if (err < 0)
94662306a36Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
94762306a36Sopenharmony_ci	dev_dbg(&dev->dev, "mbox2_boot: new boot length = %d\n",
94862306a36Sopenharmony_ci		le16_to_cpu(get_cfg_desc(config)->wTotalLength));
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	mbox2_setup_48_24_magic(dev);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	dev_info(&dev->dev, "Digidesign Mbox 2: 24bit 48kHz");
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return 0; /* Successful boot */
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	int err;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n");
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* If the Axe-Fx III has not fully booted, it will timeout when trying
96462306a36Sopenharmony_ci	 * to enable the audio streaming interface. A more generous timeout is
96562306a36Sopenharmony_ci	 * used here to detect when the Axe-Fx III has finished booting as the
96662306a36Sopenharmony_ci	 * set interface message will be acked once it has
96762306a36Sopenharmony_ci	 */
96862306a36Sopenharmony_ci	err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
96962306a36Sopenharmony_ci				USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
97062306a36Sopenharmony_ci				1, 1, NULL, 0, 120000);
97162306a36Sopenharmony_ci	if (err < 0) {
97262306a36Sopenharmony_ci		dev_err(&dev->dev,
97362306a36Sopenharmony_ci			"failed waiting for Axe-Fx III to boot: %d\n", err);
97462306a36Sopenharmony_ci		return err;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	dev_dbg(&dev->dev, "Axe-Fx III is now ready\n");
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	err = usb_set_interface(dev, 1, 0);
98062306a36Sopenharmony_ci	if (err < 0)
98162306a36Sopenharmony_ci		dev_dbg(&dev->dev,
98262306a36Sopenharmony_ci			"error stopping Axe-Fx III interface: %d\n", err);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return 0;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic void mbox3_setup_48_24_magic(struct usb_device *dev)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	/* The Mbox 3 is "little endian" */
99062306a36Sopenharmony_ci	/* max volume is: 0x0000. */
99162306a36Sopenharmony_ci	/* min volume is: 0x0080 (shown in little endian form) */
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	/* Load 48000Hz rate into buffer */
99562306a36Sopenharmony_ci	u8 com_buff[4] = {0x80, 0xbb, 0x00, 0x00};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* Set 48000Hz sample rate */
99862306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
99962306a36Sopenharmony_ci			0x01, 0x21, 0x0100, 0x0001, &com_buff, 4);  //Is this really needed?
100062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
100162306a36Sopenharmony_ci			0x01, 0x21, 0x0100, 0x8101, &com_buff, 4);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/* Deactivate Tuner */
100462306a36Sopenharmony_ci	/* on  = 0x01*/
100562306a36Sopenharmony_ci	/* off = 0x00*/
100662306a36Sopenharmony_ci	com_buff[0] = 0x00;
100762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
100862306a36Sopenharmony_ci		0x01, 0x21, 0x0003, 0x2001, &com_buff, 1);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* Set clock source to Internal (as opposed to S/PDIF) */
101162306a36Sopenharmony_ci	com_buff[0] = 0x01;
101262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
101362306a36Sopenharmony_ci			1, 0x21, 0x0100, 0x8001, &com_buff, 1);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* Mute the hardware loopbacks to start the device in a known state. */
101662306a36Sopenharmony_ci	com_buff[0] = 0x00;
101762306a36Sopenharmony_ci	com_buff[1] = 0x80;
101862306a36Sopenharmony_ci	/* Analogue input 1 left channel: */
101962306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
102062306a36Sopenharmony_ci			1, 0x21, 0x0110, 0x4001, &com_buff, 2);
102162306a36Sopenharmony_ci	/* Analogue input 1 right channel: */
102262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
102362306a36Sopenharmony_ci			1, 0x21, 0x0111, 0x4001, &com_buff, 2);
102462306a36Sopenharmony_ci	/* Analogue input 2 left channel: */
102562306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
102662306a36Sopenharmony_ci			1, 0x21, 0x0114, 0x4001, &com_buff, 2);
102762306a36Sopenharmony_ci	/* Analogue input 2 right channel: */
102862306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
102962306a36Sopenharmony_ci			1, 0x21, 0x0115, 0x4001, &com_buff, 2);
103062306a36Sopenharmony_ci	/* Analogue input 3 left channel: */
103162306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
103262306a36Sopenharmony_ci			1, 0x21, 0x0118, 0x4001, &com_buff, 2);
103362306a36Sopenharmony_ci	/* Analogue input 3 right channel: */
103462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
103562306a36Sopenharmony_ci			1, 0x21, 0x0119, 0x4001, &com_buff, 2);
103662306a36Sopenharmony_ci	/* Analogue input 4 left channel: */
103762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
103862306a36Sopenharmony_ci			1, 0x21, 0x011c, 0x4001, &com_buff, 2);
103962306a36Sopenharmony_ci	/* Analogue input 4 right channel: */
104062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
104162306a36Sopenharmony_ci			1, 0x21, 0x011d, 0x4001, &com_buff, 2);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Set software sends to output */
104462306a36Sopenharmony_ci	com_buff[0] = 0x00;
104562306a36Sopenharmony_ci	com_buff[1] = 0x00;
104662306a36Sopenharmony_ci	/* Analogue software return 1 left channel: */
104762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
104862306a36Sopenharmony_ci			1, 0x21, 0x0100, 0x4001, &com_buff, 2);
104962306a36Sopenharmony_ci	com_buff[0] = 0x00;
105062306a36Sopenharmony_ci	com_buff[1] = 0x80;
105162306a36Sopenharmony_ci	/* Analogue software return 1 right channel: */
105262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
105362306a36Sopenharmony_ci			1, 0x21, 0x0101, 0x4001, &com_buff, 2);
105462306a36Sopenharmony_ci	com_buff[0] = 0x00;
105562306a36Sopenharmony_ci	com_buff[1] = 0x80;
105662306a36Sopenharmony_ci	/* Analogue software return 2 left channel: */
105762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
105862306a36Sopenharmony_ci			1, 0x21, 0x0104, 0x4001, &com_buff, 2);
105962306a36Sopenharmony_ci	com_buff[0] = 0x00;
106062306a36Sopenharmony_ci	com_buff[1] = 0x00;
106162306a36Sopenharmony_ci	/* Analogue software return 2 right channel: */
106262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
106362306a36Sopenharmony_ci			1, 0x21, 0x0105, 0x4001, &com_buff, 2);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	com_buff[0] = 0x00;
106662306a36Sopenharmony_ci	com_buff[1] = 0x80;
106762306a36Sopenharmony_ci	/* Analogue software return 3 left channel: */
106862306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
106962306a36Sopenharmony_ci			1, 0x21, 0x0108, 0x4001, &com_buff, 2);
107062306a36Sopenharmony_ci	/* Analogue software return 3 right channel: */
107162306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
107262306a36Sopenharmony_ci			1, 0x21, 0x0109, 0x4001, &com_buff, 2);
107362306a36Sopenharmony_ci	/* Analogue software return 4 left channel: */
107462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
107562306a36Sopenharmony_ci			1, 0x21, 0x010c, 0x4001, &com_buff, 2);
107662306a36Sopenharmony_ci	/* Analogue software return 4 right channel: */
107762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
107862306a36Sopenharmony_ci			1, 0x21, 0x010d, 0x4001, &com_buff, 2);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	/* Return to muting sends */
108162306a36Sopenharmony_ci	com_buff[0] = 0x00;
108262306a36Sopenharmony_ci	com_buff[1] = 0x80;
108362306a36Sopenharmony_ci	/* Analogue fx return left channel: */
108462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
108562306a36Sopenharmony_ci			1, 0x21, 0x0120, 0x4001, &com_buff, 2);
108662306a36Sopenharmony_ci	/* Analogue fx return right channel: */
108762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
108862306a36Sopenharmony_ci			1, 0x21, 0x0121, 0x4001, &com_buff, 2);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* Analogue software input 1 fx send: */
109162306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
109262306a36Sopenharmony_ci			1, 0x21, 0x0100, 0x4201, &com_buff, 2);
109362306a36Sopenharmony_ci	/* Analogue software input 2 fx send: */
109462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
109562306a36Sopenharmony_ci			1, 0x21, 0x0101, 0x4201, &com_buff, 2);
109662306a36Sopenharmony_ci	/* Analogue software input 3 fx send: */
109762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
109862306a36Sopenharmony_ci			1, 0x21, 0x0102, 0x4201, &com_buff, 2);
109962306a36Sopenharmony_ci	/* Analogue software input 4 fx send: */
110062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
110162306a36Sopenharmony_ci			1, 0x21, 0x0103, 0x4201, &com_buff, 2);
110262306a36Sopenharmony_ci	/* Analogue input 1 fx send: */
110362306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
110462306a36Sopenharmony_ci			1, 0x21, 0x0104, 0x4201, &com_buff, 2);
110562306a36Sopenharmony_ci	/* Analogue input 2 fx send: */
110662306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
110762306a36Sopenharmony_ci			1, 0x21, 0x0105, 0x4201, &com_buff, 2);
110862306a36Sopenharmony_ci	/* Analogue input 3 fx send: */
110962306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
111062306a36Sopenharmony_ci			1, 0x21, 0x0106, 0x4201, &com_buff, 2);
111162306a36Sopenharmony_ci	/* Analogue input 4 fx send: */
111262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
111362306a36Sopenharmony_ci			1, 0x21, 0x0107, 0x4201, &com_buff, 2);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	/* Toggle allowing host control */
111662306a36Sopenharmony_ci	com_buff[0] = 0x02;
111762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
111862306a36Sopenharmony_ci			3, 0x21, 0x0000, 0x2001, &com_buff, 1);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/* Do not dim fx returns */
112162306a36Sopenharmony_ci	com_buff[0] = 0x00;
112262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
112362306a36Sopenharmony_ci			3, 0x21, 0x0002, 0x2001, &com_buff, 1);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* Do not set fx returns to mono */
112662306a36Sopenharmony_ci	com_buff[0] = 0x00;
112762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
112862306a36Sopenharmony_ci			3, 0x21, 0x0001, 0x2001, &com_buff, 1);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	/* Mute the S/PDIF hardware loopback
113162306a36Sopenharmony_ci	 * same odd volume logic here as above
113262306a36Sopenharmony_ci	 */
113362306a36Sopenharmony_ci	com_buff[0] = 0x00;
113462306a36Sopenharmony_ci	com_buff[1] = 0x80;
113562306a36Sopenharmony_ci	/* S/PDIF hardware input 1 left channel */
113662306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
113762306a36Sopenharmony_ci			1, 0x21, 0x0112, 0x4001, &com_buff, 2);
113862306a36Sopenharmony_ci	/* S/PDIF hardware input 1 right channel */
113962306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
114062306a36Sopenharmony_ci			1, 0x21, 0x0113, 0x4001, &com_buff, 2);
114162306a36Sopenharmony_ci	/* S/PDIF hardware input 2 left channel */
114262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
114362306a36Sopenharmony_ci			1, 0x21, 0x0116, 0x4001, &com_buff, 2);
114462306a36Sopenharmony_ci	/* S/PDIF hardware input 2 right channel */
114562306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
114662306a36Sopenharmony_ci			1, 0x21, 0x0117, 0x4001, &com_buff, 2);
114762306a36Sopenharmony_ci	/* S/PDIF hardware input 3 left channel */
114862306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
114962306a36Sopenharmony_ci			1, 0x21, 0x011a, 0x4001, &com_buff, 2);
115062306a36Sopenharmony_ci	/* S/PDIF hardware input 3 right channel */
115162306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
115262306a36Sopenharmony_ci			1, 0x21, 0x011b, 0x4001, &com_buff, 2);
115362306a36Sopenharmony_ci	/* S/PDIF hardware input 4 left channel */
115462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
115562306a36Sopenharmony_ci			1, 0x21, 0x011e, 0x4001, &com_buff, 2);
115662306a36Sopenharmony_ci	/* S/PDIF hardware input 4 right channel */
115762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
115862306a36Sopenharmony_ci			1, 0x21, 0x011f, 0x4001, &com_buff, 2);
115962306a36Sopenharmony_ci	/* S/PDIF software return 1 left channel */
116062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
116162306a36Sopenharmony_ci			1, 0x21, 0x0102, 0x4001, &com_buff, 2);
116262306a36Sopenharmony_ci	/* S/PDIF software return 1 right channel */
116362306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
116462306a36Sopenharmony_ci			1, 0x21, 0x0103, 0x4001, &com_buff, 2);
116562306a36Sopenharmony_ci	/* S/PDIF software return 2 left channel */
116662306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
116762306a36Sopenharmony_ci			1, 0x21, 0x0106, 0x4001, &com_buff, 2);
116862306a36Sopenharmony_ci	/* S/PDIF software return 2 right channel */
116962306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
117062306a36Sopenharmony_ci			1, 0x21, 0x0107, 0x4001, &com_buff, 2);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	com_buff[0] = 0x00;
117362306a36Sopenharmony_ci	com_buff[1] = 0x00;
117462306a36Sopenharmony_ci	/* S/PDIF software return 3 left channel */
117562306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
117662306a36Sopenharmony_ci			1, 0x21, 0x010a, 0x4001, &com_buff, 2);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	com_buff[0] = 0x00;
117962306a36Sopenharmony_ci	com_buff[1] = 0x80;
118062306a36Sopenharmony_ci	/* S/PDIF software return 3 right channel */
118162306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
118262306a36Sopenharmony_ci			1, 0x21, 0x010b, 0x4001, &com_buff, 2);
118362306a36Sopenharmony_ci	/* S/PDIF software return 4 left channel */
118462306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
118562306a36Sopenharmony_ci			1, 0x21, 0x010e, 0x4001, &com_buff, 2);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	com_buff[0] = 0x00;
118862306a36Sopenharmony_ci	com_buff[1] = 0x00;
118962306a36Sopenharmony_ci	/* S/PDIF software return 4 right channel */
119062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
119162306a36Sopenharmony_ci			1, 0x21, 0x010f, 0x4001, &com_buff, 2);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	com_buff[0] = 0x00;
119462306a36Sopenharmony_ci	com_buff[1] = 0x80;
119562306a36Sopenharmony_ci	/* S/PDIF fx returns left channel */
119662306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
119762306a36Sopenharmony_ci			1, 0x21, 0x0122, 0x4001, &com_buff, 2);
119862306a36Sopenharmony_ci	/* S/PDIF fx returns right channel */
119962306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
120062306a36Sopenharmony_ci			1, 0x21, 0x0123, 0x4001, &com_buff, 2);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* Set the dropdown "Effect" to the first option */
120362306a36Sopenharmony_ci	/* Room1  = 0x00 */
120462306a36Sopenharmony_ci	/* Room2  = 0x01 */
120562306a36Sopenharmony_ci	/* Room3  = 0x02 */
120662306a36Sopenharmony_ci	/* Hall 1 = 0x03 */
120762306a36Sopenharmony_ci	/* Hall 2 = 0x04 */
120862306a36Sopenharmony_ci	/* Plate  = 0x05 */
120962306a36Sopenharmony_ci	/* Delay  = 0x06 */
121062306a36Sopenharmony_ci	/* Echo   = 0x07 */
121162306a36Sopenharmony_ci	com_buff[0] = 0x00;
121262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
121362306a36Sopenharmony_ci			1, 0x21, 0x0200, 0x4301, &com_buff, 1);	/* max is 0xff */
121462306a36Sopenharmony_ci	/* min is 0x00 */
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	/* Set the effect duration to 0 */
121862306a36Sopenharmony_ci	/* max is 0xffff */
121962306a36Sopenharmony_ci	/* min is 0x0000 */
122062306a36Sopenharmony_ci	com_buff[0] = 0x00;
122162306a36Sopenharmony_ci	com_buff[1] = 0x00;
122262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
122362306a36Sopenharmony_ci			1, 0x21, 0x0400, 0x4301, &com_buff, 2);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* Set the effect volume and feedback to 0 */
122662306a36Sopenharmony_ci	/* max is 0xff */
122762306a36Sopenharmony_ci	/* min is 0x00 */
122862306a36Sopenharmony_ci	com_buff[0] = 0x00;
122962306a36Sopenharmony_ci	/* feedback: */
123062306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
123162306a36Sopenharmony_ci			1, 0x21, 0x0500, 0x4301, &com_buff, 1);
123262306a36Sopenharmony_ci	/* volume: */
123362306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
123462306a36Sopenharmony_ci			1, 0x21, 0x0300, 0x4301, &com_buff, 1);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/* Set soft button hold duration */
123762306a36Sopenharmony_ci	/* 0x03 = 250ms */
123862306a36Sopenharmony_ci	/* 0x05 = 500ms DEFAULT */
123962306a36Sopenharmony_ci	/* 0x08 = 750ms */
124062306a36Sopenharmony_ci	/* 0x0a = 1sec */
124162306a36Sopenharmony_ci	com_buff[0] = 0x05;
124262306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
124362306a36Sopenharmony_ci			3, 0x21, 0x0005, 0x2001, &com_buff, 1);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* Use dim LEDs for button of state */
124662306a36Sopenharmony_ci	com_buff[0] = 0x00;
124762306a36Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
124862306a36Sopenharmony_ci			3, 0x21, 0x0004, 0x2001, &com_buff, 1);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci#define MBOX3_DESCRIPTOR_SIZE	464
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic int snd_usb_mbox3_boot_quirk(struct usb_device *dev)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct usb_host_config *config = dev->actconfig;
125662306a36Sopenharmony_ci	int err;
125762306a36Sopenharmony_ci	int descriptor_size;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	descriptor_size = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (descriptor_size != MBOX3_DESCRIPTOR_SIZE) {
126262306a36Sopenharmony_ci		dev_err(&dev->dev, "Invalid descriptor size=%d.\n", descriptor_size);
126362306a36Sopenharmony_ci		return -ENODEV;
126462306a36Sopenharmony_ci	}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	dev_dbg(&dev->dev, "device initialised!\n");
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
126962306a36Sopenharmony_ci		&dev->descriptor, sizeof(dev->descriptor));
127062306a36Sopenharmony_ci	config = dev->actconfig;
127162306a36Sopenharmony_ci	if (err < 0)
127262306a36Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	err = usb_reset_configuration(dev);
127562306a36Sopenharmony_ci	if (err < 0)
127662306a36Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
127762306a36Sopenharmony_ci	dev_dbg(&dev->dev, "mbox3_boot: new boot length = %d\n",
127862306a36Sopenharmony_ci		le16_to_cpu(get_cfg_desc(config)->wTotalLength));
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	mbox3_setup_48_24_magic(dev);
128162306a36Sopenharmony_ci	dev_info(&dev->dev, "Digidesign Mbox 3: 24bit 48kHz");
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	return 0; /* Successful boot */
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci#define MICROBOOK_BUF_SIZE 128
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cistatic int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
128962306a36Sopenharmony_ci						int buf_size, int *length)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	int err, actual_length;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x01)))
129462306a36Sopenharmony_ci		return -EINVAL;
129562306a36Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
129662306a36Sopenharmony_ci				&actual_length, 1000);
129762306a36Sopenharmony_ci	if (err < 0)
129862306a36Sopenharmony_ci		return err;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "MicroBookII snd: ", DUMP_PREFIX_NONE, 16, 1,
130162306a36Sopenharmony_ci		       buf, actual_length, false);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	memset(buf, 0, buf_size);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_rcvintpipe(dev, 0x82)))
130662306a36Sopenharmony_ci		return -EINVAL;
130762306a36Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
130862306a36Sopenharmony_ci				&actual_length, 1000);
130962306a36Sopenharmony_ci	if (err < 0)
131062306a36Sopenharmony_ci		return err;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "MicroBookII rcv: ", DUMP_PREFIX_NONE, 16, 1,
131362306a36Sopenharmony_ci		       buf, actual_length, false);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	*length = actual_length;
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic int snd_usb_motu_microbookii_boot_quirk(struct usb_device *dev)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	int err, actual_length, poll_attempts = 0;
132262306a36Sopenharmony_ci	static const u8 set_samplerate_seq[] = { 0x00, 0x00, 0x00, 0x00,
132362306a36Sopenharmony_ci						 0x00, 0x00, 0x0b, 0x14,
132462306a36Sopenharmony_ci						 0x00, 0x00, 0x00, 0x01 };
132562306a36Sopenharmony_ci	static const u8 poll_ready_seq[] = { 0x00, 0x04, 0x00, 0x00,
132662306a36Sopenharmony_ci					     0x00, 0x00, 0x0b, 0x18 };
132762306a36Sopenharmony_ci	u8 *buf = kzalloc(MICROBOOK_BUF_SIZE, GFP_KERNEL);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (!buf)
133062306a36Sopenharmony_ci		return -ENOMEM;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	dev_info(&dev->dev, "Waiting for MOTU Microbook II to boot up...\n");
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	/* First we tell the device which sample rate to use. */
133562306a36Sopenharmony_ci	memcpy(buf, set_samplerate_seq, sizeof(set_samplerate_seq));
133662306a36Sopenharmony_ci	actual_length = sizeof(set_samplerate_seq);
133762306a36Sopenharmony_ci	err = snd_usb_motu_microbookii_communicate(dev, buf, MICROBOOK_BUF_SIZE,
133862306a36Sopenharmony_ci						   &actual_length);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (err < 0) {
134162306a36Sopenharmony_ci		dev_err(&dev->dev,
134262306a36Sopenharmony_ci			"failed setting the sample rate for Motu MicroBook II: %d\n",
134362306a36Sopenharmony_ci			err);
134462306a36Sopenharmony_ci		goto free_buf;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	/* Then we poll every 100 ms until the device informs of its readiness. */
134862306a36Sopenharmony_ci	while (true) {
134962306a36Sopenharmony_ci		if (++poll_attempts > 100) {
135062306a36Sopenharmony_ci			dev_err(&dev->dev,
135162306a36Sopenharmony_ci				"failed booting Motu MicroBook II: timeout\n");
135262306a36Sopenharmony_ci			err = -ENODEV;
135362306a36Sopenharmony_ci			goto free_buf;
135462306a36Sopenharmony_ci		}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		memset(buf, 0, MICROBOOK_BUF_SIZE);
135762306a36Sopenharmony_ci		memcpy(buf, poll_ready_seq, sizeof(poll_ready_seq));
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		actual_length = sizeof(poll_ready_seq);
136062306a36Sopenharmony_ci		err = snd_usb_motu_microbookii_communicate(
136162306a36Sopenharmony_ci			dev, buf, MICROBOOK_BUF_SIZE, &actual_length);
136262306a36Sopenharmony_ci		if (err < 0) {
136362306a36Sopenharmony_ci			dev_err(&dev->dev,
136462306a36Sopenharmony_ci				"failed booting Motu MicroBook II: communication error %d\n",
136562306a36Sopenharmony_ci				err);
136662306a36Sopenharmony_ci			goto free_buf;
136762306a36Sopenharmony_ci		}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		/* the device signals its readiness through a message of the
137062306a36Sopenharmony_ci		 * form
137162306a36Sopenharmony_ci		 *           XX 06 00 00 00 00 0b 18  00 00 00 01
137262306a36Sopenharmony_ci		 * If the device is not yet ready to accept audio data, the
137362306a36Sopenharmony_ci		 * last byte of that sequence is 00.
137462306a36Sopenharmony_ci		 */
137562306a36Sopenharmony_ci		if (actual_length == 12 && buf[actual_length - 1] == 1)
137662306a36Sopenharmony_ci			break;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci		msleep(100);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	dev_info(&dev->dev, "MOTU MicroBook II ready\n");
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_cifree_buf:
138462306a36Sopenharmony_ci	kfree(buf);
138562306a36Sopenharmony_ci	return err;
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	msleep(4000);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	return 0;
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci/*
139662306a36Sopenharmony_ci * Setup quirks
139762306a36Sopenharmony_ci */
139862306a36Sopenharmony_ci#define MAUDIO_SET		0x01 /* parse device_setup */
139962306a36Sopenharmony_ci#define MAUDIO_SET_COMPATIBLE	0x80 /* use only "win-compatible" interfaces */
140062306a36Sopenharmony_ci#define MAUDIO_SET_DTS		0x02 /* enable DTS Digital Output */
140162306a36Sopenharmony_ci#define MAUDIO_SET_96K		0x04 /* 48-96kHz rate if set, 8-48kHz otherwise */
140262306a36Sopenharmony_ci#define MAUDIO_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */
140362306a36Sopenharmony_ci#define MAUDIO_SET_DI		0x10 /* enable Digital Input */
140462306a36Sopenharmony_ci#define MAUDIO_SET_MASK		0x1f /* bit mask for setup value */
140562306a36Sopenharmony_ci#define MAUDIO_SET_24B_48K_DI	 0x19 /* 24bits+48kHz+Digital Input */
140662306a36Sopenharmony_ci#define MAUDIO_SET_24B_48K_NOTDI 0x09 /* 24bits+48kHz+No Digital Input */
140762306a36Sopenharmony_ci#define MAUDIO_SET_16B_48K_DI	 0x11 /* 16bits+48kHz+Digital Input */
140862306a36Sopenharmony_ci#define MAUDIO_SET_16B_48K_NOTDI 0x01 /* 16bits+48kHz+No Digital Input */
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic int quattro_skip_setting_quirk(struct snd_usb_audio *chip,
141162306a36Sopenharmony_ci				      int iface, int altno)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
141462306a36Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
141562306a36Sopenharmony_ci	 */
141662306a36Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
141762306a36Sopenharmony_ci	if (chip->setup & MAUDIO_SET) {
141862306a36Sopenharmony_ci		if (chip->setup & MAUDIO_SET_COMPATIBLE) {
141962306a36Sopenharmony_ci			if (iface != 1 && iface != 2)
142062306a36Sopenharmony_ci				return 1; /* skip all interfaces but 1 and 2 */
142162306a36Sopenharmony_ci		} else {
142262306a36Sopenharmony_ci			unsigned int mask;
142362306a36Sopenharmony_ci			if (iface == 1 || iface == 2)
142462306a36Sopenharmony_ci				return 1; /* skip interfaces 1 and 2 */
142562306a36Sopenharmony_ci			if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
142662306a36Sopenharmony_ci				return 1; /* skip this altsetting */
142762306a36Sopenharmony_ci			mask = chip->setup & MAUDIO_SET_MASK;
142862306a36Sopenharmony_ci			if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
142962306a36Sopenharmony_ci				return 1; /* skip this altsetting */
143062306a36Sopenharmony_ci			if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
143162306a36Sopenharmony_ci				return 1; /* skip this altsetting */
143262306a36Sopenharmony_ci			if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 4)
143362306a36Sopenharmony_ci				return 1; /* skip this altsetting */
143462306a36Sopenharmony_ci		}
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci	usb_audio_dbg(chip,
143762306a36Sopenharmony_ci		    "using altsetting %d for interface %d config %d\n",
143862306a36Sopenharmony_ci		    altno, iface, chip->setup);
143962306a36Sopenharmony_ci	return 0; /* keep this altsetting */
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cistatic int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
144362306a36Sopenharmony_ci					 int iface,
144462306a36Sopenharmony_ci					 int altno)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
144762306a36Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
144862306a36Sopenharmony_ci	 */
144962306a36Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	if (chip->setup & MAUDIO_SET) {
145262306a36Sopenharmony_ci		unsigned int mask;
145362306a36Sopenharmony_ci		if ((chip->setup & MAUDIO_SET_DTS) && altno != 6)
145462306a36Sopenharmony_ci			return 1; /* skip this altsetting */
145562306a36Sopenharmony_ci		if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
145662306a36Sopenharmony_ci			return 1; /* skip this altsetting */
145762306a36Sopenharmony_ci		mask = chip->setup & MAUDIO_SET_MASK;
145862306a36Sopenharmony_ci		if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
145962306a36Sopenharmony_ci			return 1; /* skip this altsetting */
146062306a36Sopenharmony_ci		if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
146162306a36Sopenharmony_ci			return 1; /* skip this altsetting */
146262306a36Sopenharmony_ci		if (mask == MAUDIO_SET_16B_48K_DI && altno != 4)
146362306a36Sopenharmony_ci			return 1; /* skip this altsetting */
146462306a36Sopenharmony_ci		if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 5)
146562306a36Sopenharmony_ci			return 1; /* skip this altsetting */
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	return 0; /* keep this altsetting */
146962306a36Sopenharmony_ci}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_cistatic int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
147262306a36Sopenharmony_ci					   int iface, int altno)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
147562306a36Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
147662306a36Sopenharmony_ci	 */
147762306a36Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	/* possible configuration where both inputs and only one output is
148062306a36Sopenharmony_ci	 *used is not supported by the current setup
148162306a36Sopenharmony_ci	 */
148262306a36Sopenharmony_ci	if (chip->setup & (MAUDIO_SET | MAUDIO_SET_24B)) {
148362306a36Sopenharmony_ci		if (chip->setup & MAUDIO_SET_96K) {
148462306a36Sopenharmony_ci			if (altno != 3 && altno != 6)
148562306a36Sopenharmony_ci				return 1;
148662306a36Sopenharmony_ci		} else if (chip->setup & MAUDIO_SET_DI) {
148762306a36Sopenharmony_ci			if (iface == 4)
148862306a36Sopenharmony_ci				return 1; /* no analog input */
148962306a36Sopenharmony_ci			if (altno != 2 && altno != 5)
149062306a36Sopenharmony_ci				return 1; /* enable only altsets 2 and 5 */
149162306a36Sopenharmony_ci		} else {
149262306a36Sopenharmony_ci			if (iface == 5)
149362306a36Sopenharmony_ci				return 1; /* disable digialt input */
149462306a36Sopenharmony_ci			if (altno != 2 && altno != 5)
149562306a36Sopenharmony_ci				return 1; /* enalbe only altsets 2 and 5 */
149662306a36Sopenharmony_ci		}
149762306a36Sopenharmony_ci	} else {
149862306a36Sopenharmony_ci		/* keep only 16-Bit mode */
149962306a36Sopenharmony_ci		if (altno != 1)
150062306a36Sopenharmony_ci			return 1;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	usb_audio_dbg(chip,
150462306a36Sopenharmony_ci		    "using altsetting %d for interface %d config %d\n",
150562306a36Sopenharmony_ci		    altno, iface, chip->setup);
150662306a36Sopenharmony_ci	return 0; /* keep this altsetting */
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cistatic int s1810c_skip_setting_quirk(struct snd_usb_audio *chip,
151062306a36Sopenharmony_ci					   int iface, int altno)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	/*
151362306a36Sopenharmony_ci	 * Altno settings:
151462306a36Sopenharmony_ci	 *
151562306a36Sopenharmony_ci	 * Playback (Interface 1):
151662306a36Sopenharmony_ci	 * 1: 6 Analog + 2 S/PDIF
151762306a36Sopenharmony_ci	 * 2: 6 Analog + 2 S/PDIF
151862306a36Sopenharmony_ci	 * 3: 6 Analog
151962306a36Sopenharmony_ci	 *
152062306a36Sopenharmony_ci	 * Capture (Interface 2):
152162306a36Sopenharmony_ci	 * 1: 8 Analog + 2 S/PDIF + 8 ADAT
152262306a36Sopenharmony_ci	 * 2: 8 Analog + 2 S/PDIF + 4 ADAT
152362306a36Sopenharmony_ci	 * 3: 8 Analog
152462306a36Sopenharmony_ci	 */
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/*
152762306a36Sopenharmony_ci	 * I'll leave 2 as the default one and
152862306a36Sopenharmony_ci	 * use device_setup to switch to the
152962306a36Sopenharmony_ci	 * other two.
153062306a36Sopenharmony_ci	 */
153162306a36Sopenharmony_ci	if ((chip->setup == 0 || chip->setup > 2) && altno != 2)
153262306a36Sopenharmony_ci		return 1;
153362306a36Sopenharmony_ci	else if (chip->setup == 1 && altno != 1)
153462306a36Sopenharmony_ci		return 1;
153562306a36Sopenharmony_ci	else if (chip->setup == 2 && altno != 3)
153662306a36Sopenharmony_ci		return 1;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	return 0;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ciint snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
154262306a36Sopenharmony_ci				  int iface,
154362306a36Sopenharmony_ci				  int altno)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	/* audiophile usb: skip altsets incompatible with device_setup */
154662306a36Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2003))
154762306a36Sopenharmony_ci		return audiophile_skip_setting_quirk(chip, iface, altno);
154862306a36Sopenharmony_ci	/* quattro usb: skip altsets incompatible with device_setup */
154962306a36Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2001))
155062306a36Sopenharmony_ci		return quattro_skip_setting_quirk(chip, iface, altno);
155162306a36Sopenharmony_ci	/* fasttrackpro usb: skip altsets incompatible with device_setup */
155262306a36Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2012))
155362306a36Sopenharmony_ci		return fasttrackpro_skip_setting_quirk(chip, iface, altno);
155462306a36Sopenharmony_ci	/* presonus studio 1810c: skip altsets incompatible with device_setup */
155562306a36Sopenharmony_ci	if (chip->usb_id == USB_ID(0x194f, 0x010c))
155662306a36Sopenharmony_ci		return s1810c_skip_setting_quirk(chip, iface, altno);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	return 0;
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ciint snd_usb_apply_boot_quirk(struct usb_device *dev,
156362306a36Sopenharmony_ci			     struct usb_interface *intf,
156462306a36Sopenharmony_ci			     const struct snd_usb_audio_quirk *quirk,
156562306a36Sopenharmony_ci			     unsigned int id)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	switch (id) {
156862306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3000):
156962306a36Sopenharmony_ci		/* SB Extigy needs special boot-up sequence */
157062306a36Sopenharmony_ci		/* if more models come, this will go to the quirk list. */
157162306a36Sopenharmony_ci		return snd_usb_extigy_boot_quirk(dev, intf);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3020):
157462306a36Sopenharmony_ci		/* SB Audigy 2 NX needs its own boot-up magic, too */
157562306a36Sopenharmony_ci		return snd_usb_audigy2nx_boot_quirk(dev);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	case USB_ID(0x10f5, 0x0200):
157862306a36Sopenharmony_ci		/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
157962306a36Sopenharmony_ci		return snd_usb_cm106_boot_quirk(dev);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	case USB_ID(0x0d8c, 0x0102):
158262306a36Sopenharmony_ci		/* C-Media CM6206 / CM106-Like Sound Device */
158362306a36Sopenharmony_ci	case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */
158462306a36Sopenharmony_ci		return snd_usb_cm6206_boot_quirk(dev);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	case USB_ID(0x0dba, 0x3000):
158762306a36Sopenharmony_ci		/* Digidesign Mbox 2 */
158862306a36Sopenharmony_ci		return snd_usb_mbox2_boot_quirk(dev);
158962306a36Sopenharmony_ci	case USB_ID(0x0dba, 0x5000):
159062306a36Sopenharmony_ci		/* Digidesign Mbox 3 */
159162306a36Sopenharmony_ci		return snd_usb_mbox3_boot_quirk(dev);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */
159562306a36Sopenharmony_ci	case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */
159662306a36Sopenharmony_ci		return snd_usb_novation_boot_quirk(dev);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	case USB_ID(0x133e, 0x0815):
159962306a36Sopenharmony_ci		/* Access Music VirusTI Desktop */
160062306a36Sopenharmony_ci		return snd_usb_accessmusic_boot_quirk(dev);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */
160362306a36Sopenharmony_ci	case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
160462306a36Sopenharmony_ci	case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
160562306a36Sopenharmony_ci		return snd_usb_nativeinstruments_boot_quirk(dev);
160662306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
160762306a36Sopenharmony_ci		return snd_usb_fasttrackpro_boot_quirk(dev);
160862306a36Sopenharmony_ci	case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */
160962306a36Sopenharmony_ci		return snd_usb_gamecon780_boot_quirk(dev);
161062306a36Sopenharmony_ci	case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */
161162306a36Sopenharmony_ci		return snd_usb_axefx3_boot_quirk(dev);
161262306a36Sopenharmony_ci	case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */
161362306a36Sopenharmony_ci		/*
161462306a36Sopenharmony_ci		 * For some reason interface 3 with vendor-spec class is
161562306a36Sopenharmony_ci		 * detected on MicroBook IIc.
161662306a36Sopenharmony_ci		 */
161762306a36Sopenharmony_ci		if (get_iface_desc(intf->altsetting)->bInterfaceClass ==
161862306a36Sopenharmony_ci		    USB_CLASS_VENDOR_SPEC &&
161962306a36Sopenharmony_ci		    get_iface_desc(intf->altsetting)->bInterfaceNumber < 3)
162062306a36Sopenharmony_ci			return snd_usb_motu_microbookii_boot_quirk(dev);
162162306a36Sopenharmony_ci		break;
162262306a36Sopenharmony_ci	}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	return 0;
162562306a36Sopenharmony_ci}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ciint snd_usb_apply_boot_quirk_once(struct usb_device *dev,
162862306a36Sopenharmony_ci				  struct usb_interface *intf,
162962306a36Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk,
163062306a36Sopenharmony_ci				  unsigned int id)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	switch (id) {
163362306a36Sopenharmony_ci	case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */
163462306a36Sopenharmony_ci		return snd_usb_motu_m_series_boot_quirk(dev);
163562306a36Sopenharmony_ci	}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	return 0;
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci/*
164162306a36Sopenharmony_ci * check if the device uses big-endian samples
164262306a36Sopenharmony_ci */
164362306a36Sopenharmony_ciint snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
164462306a36Sopenharmony_ci				 const struct audioformat *fp)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	/* it depends on altsetting whether the device is big-endian or not */
164762306a36Sopenharmony_ci	switch (chip->usb_id) {
164862306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
164962306a36Sopenharmony_ci		if (fp->altsetting == 2 || fp->altsetting == 3 ||
165062306a36Sopenharmony_ci			fp->altsetting == 5 || fp->altsetting == 6)
165162306a36Sopenharmony_ci			return 1;
165262306a36Sopenharmony_ci		break;
165362306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
165462306a36Sopenharmony_ci		if (chip->setup == 0x00 ||
165562306a36Sopenharmony_ci			fp->altsetting == 1 || fp->altsetting == 2 ||
165662306a36Sopenharmony_ci			fp->altsetting == 3)
165762306a36Sopenharmony_ci			return 1;
165862306a36Sopenharmony_ci		break;
165962306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro */
166062306a36Sopenharmony_ci		if (fp->altsetting == 2 || fp->altsetting == 3 ||
166162306a36Sopenharmony_ci			fp->altsetting == 5 || fp->altsetting == 6)
166262306a36Sopenharmony_ci			return 1;
166362306a36Sopenharmony_ci		break;
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci	return 0;
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci/*
166962306a36Sopenharmony_ci * For E-Mu 0404USB/0202USB/TrackerPre/0204 sample rate should be set for device,
167062306a36Sopenharmony_ci * not for interface.
167162306a36Sopenharmony_ci */
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cienum {
167462306a36Sopenharmony_ci	EMU_QUIRK_SR_44100HZ = 0,
167562306a36Sopenharmony_ci	EMU_QUIRK_SR_48000HZ,
167662306a36Sopenharmony_ci	EMU_QUIRK_SR_88200HZ,
167762306a36Sopenharmony_ci	EMU_QUIRK_SR_96000HZ,
167862306a36Sopenharmony_ci	EMU_QUIRK_SR_176400HZ,
167962306a36Sopenharmony_ci	EMU_QUIRK_SR_192000HZ
168062306a36Sopenharmony_ci};
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic void set_format_emu_quirk(struct snd_usb_substream *subs,
168362306a36Sopenharmony_ci				 const struct audioformat *fmt)
168462306a36Sopenharmony_ci{
168562306a36Sopenharmony_ci	unsigned char emu_samplerate_id = 0;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	/* When capture is active
168862306a36Sopenharmony_ci	 * sample rate shouldn't be changed
168962306a36Sopenharmony_ci	 * by playback substream
169062306a36Sopenharmony_ci	 */
169162306a36Sopenharmony_ci	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
169262306a36Sopenharmony_ci		if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].cur_audiofmt)
169362306a36Sopenharmony_ci			return;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	switch (fmt->rate_min) {
169762306a36Sopenharmony_ci	case 48000:
169862306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_48000HZ;
169962306a36Sopenharmony_ci		break;
170062306a36Sopenharmony_ci	case 88200:
170162306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_88200HZ;
170262306a36Sopenharmony_ci		break;
170362306a36Sopenharmony_ci	case 96000:
170462306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_96000HZ;
170562306a36Sopenharmony_ci		break;
170662306a36Sopenharmony_ci	case 176400:
170762306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_176400HZ;
170862306a36Sopenharmony_ci		break;
170962306a36Sopenharmony_ci	case 192000:
171062306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_192000HZ;
171162306a36Sopenharmony_ci		break;
171262306a36Sopenharmony_ci	default:
171362306a36Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_44100HZ;
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
171762306a36Sopenharmony_ci	subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs,
172162306a36Sopenharmony_ci					u16 windex)
172262306a36Sopenharmony_ci{
172362306a36Sopenharmony_ci	unsigned int cur_rate = subs->data_endpoint->cur_rate;
172462306a36Sopenharmony_ci	u8 sr[3];
172562306a36Sopenharmony_ci	// Convert to little endian
172662306a36Sopenharmony_ci	sr[0] = cur_rate & 0xff;
172762306a36Sopenharmony_ci	sr[1] = (cur_rate >> 8) & 0xff;
172862306a36Sopenharmony_ci	sr[2] = (cur_rate >> 16) & 0xff;
172962306a36Sopenharmony_ci	usb_set_interface(subs->dev, 0, 1);
173062306a36Sopenharmony_ci	// we should derive windex from fmt-sync_ep but it's not set
173162306a36Sopenharmony_ci	snd_usb_ctl_msg(subs->stream->chip->dev,
173262306a36Sopenharmony_ci		usb_sndctrlpipe(subs->stream->chip->dev, 0),
173362306a36Sopenharmony_ci		0x01, 0x22, 0x0100, windex, &sr, 0x0003);
173462306a36Sopenharmony_ci	return 0;
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_civoid snd_usb_set_format_quirk(struct snd_usb_substream *subs,
173862306a36Sopenharmony_ci			      const struct audioformat *fmt)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	switch (subs->stream->chip->usb_id) {
174162306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
174262306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
174362306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
174462306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
174562306a36Sopenharmony_ci		set_format_emu_quirk(subs, fmt);
174662306a36Sopenharmony_ci		break;
174762306a36Sopenharmony_ci	case USB_ID(0x534d, 0x0021): /* MacroSilicon MS2100/MS2106 */
174862306a36Sopenharmony_ci	case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
174962306a36Sopenharmony_ci		subs->stream_offset_adj = 2;
175062306a36Sopenharmony_ci		break;
175162306a36Sopenharmony_ci	case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */
175262306a36Sopenharmony_ci		pioneer_djm_set_format_quirk(subs, 0x0082);
175362306a36Sopenharmony_ci		break;
175462306a36Sopenharmony_ci	case USB_ID(0x08e4, 0x017f): /* Pioneer DJM-750 */
175562306a36Sopenharmony_ci	case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */
175662306a36Sopenharmony_ci		pioneer_djm_set_format_quirk(subs, 0x0086);
175762306a36Sopenharmony_ci		break;
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ciint snd_usb_select_mode_quirk(struct snd_usb_audio *chip,
176262306a36Sopenharmony_ci			      const struct audioformat *fmt)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	struct usb_device *dev = chip->dev;
176562306a36Sopenharmony_ci	int err;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (chip->quirk_flags & QUIRK_FLAG_ITF_USB_DSD_DAC) {
176862306a36Sopenharmony_ci		/* First switch to alt set 0, otherwise the mode switch cmd
176962306a36Sopenharmony_ci		 * will not be accepted by the DAC
177062306a36Sopenharmony_ci		 */
177162306a36Sopenharmony_ci		err = usb_set_interface(dev, fmt->iface, 0);
177262306a36Sopenharmony_ci		if (err < 0)
177362306a36Sopenharmony_ci			return err;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		msleep(20); /* Delay needed after setting the interface */
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci		/* Vendor mode switch cmd is required. */
177862306a36Sopenharmony_ci		if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) {
177962306a36Sopenharmony_ci			/* DSD mode (DSD_U32) requested */
178062306a36Sopenharmony_ci			err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
178162306a36Sopenharmony_ci					      USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
178262306a36Sopenharmony_ci					      1, 1, NULL, 0);
178362306a36Sopenharmony_ci			if (err < 0)
178462306a36Sopenharmony_ci				return err;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci		} else {
178762306a36Sopenharmony_ci			/* PCM or DOP mode (S32) requested */
178862306a36Sopenharmony_ci			/* PCM mode (S16) requested */
178962306a36Sopenharmony_ci			err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
179062306a36Sopenharmony_ci					      USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
179162306a36Sopenharmony_ci					      0, 1, NULL, 0);
179262306a36Sopenharmony_ci			if (err < 0)
179362306a36Sopenharmony_ci				return err;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci		}
179662306a36Sopenharmony_ci		msleep(20);
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci	return 0;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_civoid snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
180262306a36Sopenharmony_ci{
180362306a36Sopenharmony_ci	/*
180462306a36Sopenharmony_ci	 * "Playback Design" products send bogus feedback data at the start
180562306a36Sopenharmony_ci	 * of the stream. Ignore them.
180662306a36Sopenharmony_ci	 */
180762306a36Sopenharmony_ci	if (USB_ID_VENDOR(ep->chip->usb_id) == 0x23ba &&
180862306a36Sopenharmony_ci	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
180962306a36Sopenharmony_ci		ep->skip_packets = 4;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/*
181262306a36Sopenharmony_ci	 * M-Audio Fast Track C400/C600 - when packets are not skipped, real
181362306a36Sopenharmony_ci	 * world latency varies by approx. +/- 50 frames (at 96kHz) each time
181462306a36Sopenharmony_ci	 * the stream is (re)started. When skipping packets 16 at endpoint
181562306a36Sopenharmony_ci	 * start up, the real world latency is stable within +/- 1 frame (also
181662306a36Sopenharmony_ci	 * across power cycles).
181762306a36Sopenharmony_ci	 */
181862306a36Sopenharmony_ci	if ((ep->chip->usb_id == USB_ID(0x0763, 0x2030) ||
181962306a36Sopenharmony_ci	     ep->chip->usb_id == USB_ID(0x0763, 0x2031)) &&
182062306a36Sopenharmony_ci	    ep->type == SND_USB_ENDPOINT_TYPE_DATA)
182162306a36Sopenharmony_ci		ep->skip_packets = 16;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* Work around devices that report unreasonable feedback data */
182462306a36Sopenharmony_ci	if ((ep->chip->usb_id == USB_ID(0x0644, 0x8038) ||  /* TEAC UD-H01 */
182562306a36Sopenharmony_ci	     ep->chip->usb_id == USB_ID(0x1852, 0x5034)) && /* T+A Dac8 */
182662306a36Sopenharmony_ci	    ep->syncmaxsize == 4)
182762306a36Sopenharmony_ci		ep->tenor_fb_quirk = 1;
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci/* quirk applied after snd_usb_ctl_msg(); not applied during boot quirks */
183162306a36Sopenharmony_civoid snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
183262306a36Sopenharmony_ci			   __u8 request, __u8 requesttype, __u16 value,
183362306a36Sopenharmony_ci			   __u16 index, void *data, __u16 size)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	struct snd_usb_audio *chip = dev_get_drvdata(&dev->dev);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	if (!chip || (requesttype & USB_TYPE_MASK) != USB_TYPE_CLASS)
183862306a36Sopenharmony_ci		return;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY)
184162306a36Sopenharmony_ci		msleep(20);
184262306a36Sopenharmony_ci	else if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY_1M)
184362306a36Sopenharmony_ci		usleep_range(1000, 2000);
184462306a36Sopenharmony_ci	else if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY_5M)
184562306a36Sopenharmony_ci		usleep_range(5000, 6000);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci/*
184962306a36Sopenharmony_ci * snd_usb_interface_dsd_format_quirks() is called from format.c to
185062306a36Sopenharmony_ci * augment the PCM format bit-field for DSD types. The UAC standards
185162306a36Sopenharmony_ci * don't have a designated bit field to denote DSD-capable interfaces,
185262306a36Sopenharmony_ci * hence all hardware that is known to support this format has to be
185362306a36Sopenharmony_ci * listed here.
185462306a36Sopenharmony_ci */
185562306a36Sopenharmony_ciu64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
185662306a36Sopenharmony_ci					struct audioformat *fp,
185762306a36Sopenharmony_ci					unsigned int sample_bytes)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	struct usb_interface *iface;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	/* Playback Designs */
186262306a36Sopenharmony_ci	if (USB_ID_VENDOR(chip->usb_id) == 0x23ba &&
186362306a36Sopenharmony_ci	    USB_ID_PRODUCT(chip->usb_id) < 0x0110) {
186462306a36Sopenharmony_ci		switch (fp->altsetting) {
186562306a36Sopenharmony_ci		case 1:
186662306a36Sopenharmony_ci			fp->dsd_dop = true;
186762306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
186862306a36Sopenharmony_ci		case 2:
186962306a36Sopenharmony_ci			fp->dsd_bitrev = true;
187062306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U8;
187162306a36Sopenharmony_ci		case 3:
187262306a36Sopenharmony_ci			fp->dsd_bitrev = true;
187362306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
187462306a36Sopenharmony_ci		}
187562306a36Sopenharmony_ci	}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	/* XMOS based USB DACs */
187862306a36Sopenharmony_ci	switch (chip->usb_id) {
187962306a36Sopenharmony_ci	case USB_ID(0x139f, 0x5504): /* Nagra DAC */
188062306a36Sopenharmony_ci	case USB_ID(0x20b1, 0x3089): /* Mola-Mola DAC */
188162306a36Sopenharmony_ci	case USB_ID(0x2522, 0x0007): /* LH Labs Geek Out 1V5 */
188262306a36Sopenharmony_ci	case USB_ID(0x2522, 0x0009): /* LH Labs Geek Pulse X Inifinity 2V0 */
188362306a36Sopenharmony_ci	case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */
188462306a36Sopenharmony_ci	case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */
188562306a36Sopenharmony_ci		if (fp->altsetting == 2)
188662306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
188762306a36Sopenharmony_ci		break;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */
189062306a36Sopenharmony_ci	case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */
189162306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x06b2): /* NuPrime DAC-10 */
189262306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x06b4): /* NuPrime Audio HD-AVP/AVA */
189362306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */
189462306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x09d8): /* NuPrime IDA-8 */
189562306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */
189662306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */
189762306a36Sopenharmony_ci	case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */
189862306a36Sopenharmony_ci	case USB_ID(0x20a0, 0x4143): /* WaveIO USB Audio 2.0 */
189962306a36Sopenharmony_ci	case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */
190062306a36Sopenharmony_ci	case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */
190162306a36Sopenharmony_ci	case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */
190262306a36Sopenharmony_ci	case USB_ID(0x2622, 0x0041): /* Audiolab M-DAC+ */
190362306a36Sopenharmony_ci	case USB_ID(0x278b, 0x5100): /* Rotel RC-1590 */
190462306a36Sopenharmony_ci	case USB_ID(0x27f7, 0x3002): /* W4S DAC-2v2SE */
190562306a36Sopenharmony_ci	case USB_ID(0x29a2, 0x0086): /* Mutec MC3+ USB */
190662306a36Sopenharmony_ci	case USB_ID(0x6b42, 0x0042): /* MSB Technology */
190762306a36Sopenharmony_ci		if (fp->altsetting == 3)
190862306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
190962306a36Sopenharmony_ci		break;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* Amanero Combo384 USB based DACs with native DSD support */
191262306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x071a):  /* Amanero - Combo384 */
191362306a36Sopenharmony_ci		if (fp->altsetting == 2) {
191462306a36Sopenharmony_ci			switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) {
191562306a36Sopenharmony_ci			case 0x199:
191662306a36Sopenharmony_ci				return SNDRV_PCM_FMTBIT_DSD_U32_LE;
191762306a36Sopenharmony_ci			case 0x19b:
191862306a36Sopenharmony_ci			case 0x203:
191962306a36Sopenharmony_ci				return SNDRV_PCM_FMTBIT_DSD_U32_BE;
192062306a36Sopenharmony_ci			default:
192162306a36Sopenharmony_ci				break;
192262306a36Sopenharmony_ci			}
192362306a36Sopenharmony_ci		}
192462306a36Sopenharmony_ci		break;
192562306a36Sopenharmony_ci	case USB_ID(0x16d0, 0x0a23):
192662306a36Sopenharmony_ci		if (fp->altsetting == 2)
192762306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
192862306a36Sopenharmony_ci		break;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	default:
193162306a36Sopenharmony_ci		break;
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	/* ITF-USB DSD based DACs */
193562306a36Sopenharmony_ci	if (chip->quirk_flags & QUIRK_FLAG_ITF_USB_DSD_DAC) {
193662306a36Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, fp->iface);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci		/* Altsetting 2 support native DSD if the num of altsets is
193962306a36Sopenharmony_ci		 * three (0-2),
194062306a36Sopenharmony_ci		 * Altsetting 3 support native DSD if the num of altsets is
194162306a36Sopenharmony_ci		 * four (0-3).
194262306a36Sopenharmony_ci		 */
194362306a36Sopenharmony_ci		if (fp->altsetting == iface->num_altsetting - 1)
194462306a36Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/* Mostly generic method to detect many DSD-capable implementations */
194862306a36Sopenharmony_ci	if ((chip->quirk_flags & QUIRK_FLAG_DSD_RAW) && fp->dsd_raw)
194962306a36Sopenharmony_ci		return SNDRV_PCM_FMTBIT_DSD_U32_BE;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	return 0;
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_civoid snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
195562306a36Sopenharmony_ci					  struct audioformat *fp,
195662306a36Sopenharmony_ci					  int stream)
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	switch (chip->usb_id) {
195962306a36Sopenharmony_ci	case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
196062306a36Sopenharmony_ci		/* Optoplay sets the sample rate attribute although
196162306a36Sopenharmony_ci		 * it seems not supporting it in fact.
196262306a36Sopenharmony_ci		 */
196362306a36Sopenharmony_ci		fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
196462306a36Sopenharmony_ci		break;
196562306a36Sopenharmony_ci	case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
196662306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
196762306a36Sopenharmony_ci		/* doesn't set the sample rate attribute, but supports it */
196862306a36Sopenharmony_ci		fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
196962306a36Sopenharmony_ci		break;
197062306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
197162306a36Sopenharmony_ci	case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
197262306a36Sopenharmony_ci	case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
197362306a36Sopenharmony_ci	case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
197462306a36Sopenharmony_ci					an older model 77d:223) */
197562306a36Sopenharmony_ci	/*
197662306a36Sopenharmony_ci	 * plantronics headset and Griffin iMic have set adaptive-in
197762306a36Sopenharmony_ci	 * although it's really not...
197862306a36Sopenharmony_ci	 */
197962306a36Sopenharmony_ci		fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
198062306a36Sopenharmony_ci		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
198162306a36Sopenharmony_ci			fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
198262306a36Sopenharmony_ci		else
198362306a36Sopenharmony_ci			fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
198462306a36Sopenharmony_ci		break;
198562306a36Sopenharmony_ci	case USB_ID(0x07fd, 0x0004):  /* MOTU MicroBook IIc */
198662306a36Sopenharmony_ci		/*
198762306a36Sopenharmony_ci		 * MaxPacketsOnly attribute is erroneously set in endpoint
198862306a36Sopenharmony_ci		 * descriptors. As a result this card produces noise with
198962306a36Sopenharmony_ci		 * all sample rates other than 96 kHz.
199062306a36Sopenharmony_ci		 */
199162306a36Sopenharmony_ci		fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX;
199262306a36Sopenharmony_ci		break;
199362306a36Sopenharmony_ci	case USB_ID(0x1224, 0x2a25):  /* Jieli Technology USB PHY 2.0 */
199462306a36Sopenharmony_ci		/* mic works only when ep packet size is set to wMaxPacketSize */
199562306a36Sopenharmony_ci		fp->attributes |= UAC_EP_CS_ATTR_FILL_MAX;
199662306a36Sopenharmony_ci		break;
199762306a36Sopenharmony_ci	case USB_ID(0x3511, 0x2b1e): /* Opencomm2 UC USB Bluetooth dongle */
199862306a36Sopenharmony_ci		/* mic works only when ep pitch control is not set */
199962306a36Sopenharmony_ci		if (stream == SNDRV_PCM_STREAM_CAPTURE)
200062306a36Sopenharmony_ci			fp->attributes &= ~UAC_EP_CS_ATTR_PITCH_CONTROL;
200162306a36Sopenharmony_ci		break;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci/*
200662306a36Sopenharmony_ci * driver behavior quirk flags
200762306a36Sopenharmony_ci */
200862306a36Sopenharmony_cistruct usb_audio_quirk_flags_table {
200962306a36Sopenharmony_ci	u32 id;
201062306a36Sopenharmony_ci	u32 flags;
201162306a36Sopenharmony_ci};
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci#define DEVICE_FLG(vid, pid, _flags) \
201462306a36Sopenharmony_ci	{ .id = USB_ID(vid, pid), .flags = (_flags) }
201562306a36Sopenharmony_ci#define VENDOR_FLG(vid, _flags) DEVICE_FLG(vid, 0, _flags)
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistatic const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
201862306a36Sopenharmony_ci	/* Device matches */
201962306a36Sopenharmony_ci	DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */
202062306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
202162306a36Sopenharmony_ci	DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */
202262306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
202362306a36Sopenharmony_ci	DEVICE_FLG(0x045e, 0x083c, /* MS USB Link headset */
202462306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY |
202562306a36Sopenharmony_ci		   QUIRK_FLAG_DISABLE_AUTOSUSPEND),
202662306a36Sopenharmony_ci	DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */
202762306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY_1M),
202862306a36Sopenharmony_ci	DEVICE_FLG(0x046d, 0x0991, /* Logitech QuickCam Pro */
202962306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
203062306a36Sopenharmony_ci	DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */
203162306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
203262306a36Sopenharmony_ci	DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */
203362306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
203462306a36Sopenharmony_ci	DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */
203562306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
203662306a36Sopenharmony_ci	DEVICE_FLG(0x04d8, 0xfeea, /* Benchmark DAC1 Pre */
203762306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
203862306a36Sopenharmony_ci	DEVICE_FLG(0x04e8, 0xa051, /* Samsung USBC Headset (AKG) */
203962306a36Sopenharmony_ci		   QUIRK_FLAG_SKIP_CLOCK_SELECTOR | QUIRK_FLAG_CTL_MSG_DELAY_5M),
204062306a36Sopenharmony_ci	DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
204162306a36Sopenharmony_ci		   QUIRK_FLAG_IFACE_SKIP_CLOSE),
204262306a36Sopenharmony_ci	DEVICE_FLG(0x054c, 0x0b8c, /* Sony WALKMAN NW-A45 DAC */
204362306a36Sopenharmony_ci		   QUIRK_FLAG_SET_IFACE_FIRST),
204462306a36Sopenharmony_ci	DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */
204562306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
204662306a36Sopenharmony_ci	DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */
204762306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
204862306a36Sopenharmony_ci	DEVICE_FLG(0x05a7, 0x1020, /* Bose Companion 5 */
204962306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
205062306a36Sopenharmony_ci	DEVICE_FLG(0x05e1, 0x0408, /* Syntek STK1160 */
205162306a36Sopenharmony_ci		   QUIRK_FLAG_ALIGN_TRANSFER),
205262306a36Sopenharmony_ci	DEVICE_FLG(0x05e1, 0x0480, /* Hauppauge Woodbury */
205362306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
205462306a36Sopenharmony_ci	DEVICE_FLG(0x0644, 0x8043, /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
205562306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
205662306a36Sopenharmony_ci		   QUIRK_FLAG_IFACE_DELAY),
205762306a36Sopenharmony_ci	DEVICE_FLG(0x0644, 0x8044, /* Esoteric D-05X */
205862306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
205962306a36Sopenharmony_ci		   QUIRK_FLAG_IFACE_DELAY),
206062306a36Sopenharmony_ci	DEVICE_FLG(0x0644, 0x804a, /* TEAC UD-301 */
206162306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
206262306a36Sopenharmony_ci		   QUIRK_FLAG_IFACE_DELAY),
206362306a36Sopenharmony_ci	DEVICE_FLG(0x0644, 0x805f, /* TEAC Model 12 */
206462306a36Sopenharmony_ci		   QUIRK_FLAG_FORCE_IFACE_RESET),
206562306a36Sopenharmony_ci	DEVICE_FLG(0x0644, 0x806b, /* TEAC UD-701 */
206662306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
206762306a36Sopenharmony_ci		   QUIRK_FLAG_IFACE_DELAY),
206862306a36Sopenharmony_ci	DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
206962306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
207062306a36Sopenharmony_ci	DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */
207162306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
207262306a36Sopenharmony_ci	DEVICE_FLG(0x0711, 0x5800, /* MCT Trigger 5 USB-to-HDMI */
207362306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
207462306a36Sopenharmony_ci	DEVICE_FLG(0x074d, 0x3553, /* Outlaw RR2150 (Micronas UAC3553B) */
207562306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
207662306a36Sopenharmony_ci	DEVICE_FLG(0x0763, 0x2030, /* M-Audio Fast Track C400 */
207762306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
207862306a36Sopenharmony_ci	DEVICE_FLG(0x0763, 0x2031, /* M-Audio Fast Track C600 */
207962306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
208062306a36Sopenharmony_ci	DEVICE_FLG(0x07fd, 0x000b, /* MOTU M Series 2nd hardware revision */
208162306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M),
208262306a36Sopenharmony_ci	DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */
208362306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
208462306a36Sopenharmony_ci	DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
208562306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M),
208662306a36Sopenharmony_ci	DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
208762306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M),
208862306a36Sopenharmony_ci	DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
208962306a36Sopenharmony_ci		   QUIRK_FLAG_FIXED_RATE),
209062306a36Sopenharmony_ci	DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
209162306a36Sopenharmony_ci		   QUIRK_FLAG_FIXED_RATE),
209262306a36Sopenharmony_ci	DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */
209362306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
209462306a36Sopenharmony_ci	DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
209562306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
209662306a36Sopenharmony_ci	DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
209762306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
209862306a36Sopenharmony_ci	DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */
209962306a36Sopenharmony_ci		   QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
210062306a36Sopenharmony_ci	DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
210162306a36Sopenharmony_ci		   QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
210262306a36Sopenharmony_ci	DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
210362306a36Sopenharmony_ci		   QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
210462306a36Sopenharmony_ci	DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
210562306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
210662306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
210762306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
210862306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x1003, /* Denon DA-300USB */
210962306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
211062306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x3005, /* Marantz HD-DAC1 */
211162306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
211262306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x3006, /* Marantz SA-14S1 */
211362306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
211462306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x300b, /* Marantz SA-KI RUBY / SA-12 */
211562306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
211662306a36Sopenharmony_ci	DEVICE_FLG(0x154e, 0x500e, /* Denon DN-X1600 */
211762306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CLOCK_SOURCE),
211862306a36Sopenharmony_ci	DEVICE_FLG(0x1686, 0x00dd, /* Zoom R16/24 */
211962306a36Sopenharmony_ci		   QUIRK_FLAG_TX_LENGTH | QUIRK_FLAG_CTL_MSG_DELAY_1M),
212062306a36Sopenharmony_ci	DEVICE_FLG(0x17aa, 0x1046, /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
212162306a36Sopenharmony_ci		   QUIRK_FLAG_DISABLE_AUTOSUSPEND),
212262306a36Sopenharmony_ci	DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
212362306a36Sopenharmony_ci		   QUIRK_FLAG_DISABLE_AUTOSUSPEND),
212462306a36Sopenharmony_ci	DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */
212562306a36Sopenharmony_ci		   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
212662306a36Sopenharmony_ci	DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */
212762306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
212862306a36Sopenharmony_ci	DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */
212962306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
213062306a36Sopenharmony_ci	DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
213162306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
213262306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
213362306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
213462306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
213562306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
213662306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7210, /* Hauppauge HVR-950Q */
213762306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
213862306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7211, /* Hauppauge HVR-950Q-MXL */
213962306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
214062306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7213, /* Hauppauge HVR-950Q */
214162306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
214262306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7217, /* Hauppauge HVR-950Q */
214362306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
214462306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x721b, /* Hauppauge HVR-950Q */
214562306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
214662306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x721e, /* Hauppauge HVR-950Q */
214762306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
214862306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x721f, /* Hauppauge HVR-950Q */
214962306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
215062306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7240, /* Hauppauge HVR-850 */
215162306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
215262306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7260, /* Hauppauge HVR-950Q */
215362306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
215462306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7270, /* Hauppauge HVR-950Q */
215562306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
215662306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7280, /* Hauppauge HVR-950Q */
215762306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
215862306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x7281, /* Hauppauge HVR-950Q-MXL */
215962306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
216062306a36Sopenharmony_ci	DEVICE_FLG(0x2040, 0x8200, /* Hauppauge Woodbury */
216162306a36Sopenharmony_ci		   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
216262306a36Sopenharmony_ci	DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */
216362306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
216462306a36Sopenharmony_ci	DEVICE_FLG(0x21b4, 0x0230, /* Ayre QB-9 Twenty */
216562306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
216662306a36Sopenharmony_ci	DEVICE_FLG(0x21b4, 0x0232, /* Ayre QX-5 Twenty */
216762306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
216862306a36Sopenharmony_ci	DEVICE_FLG(0x2522, 0x0007, /* LH Labs Geek Out HD Audio 1V5 */
216962306a36Sopenharmony_ci		   QUIRK_FLAG_SET_IFACE_FIRST),
217062306a36Sopenharmony_ci	DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */
217162306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
217262306a36Sopenharmony_ci	DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
217362306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
217462306a36Sopenharmony_ci	DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
217562306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
217662306a36Sopenharmony_ci	DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
217762306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
217862306a36Sopenharmony_ci	DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
217962306a36Sopenharmony_ci		   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
218062306a36Sopenharmony_ci	DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */
218162306a36Sopenharmony_ci		   QUIRK_FLAG_IGNORE_CTL_ERROR),
218262306a36Sopenharmony_ci	DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
218362306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
218462306a36Sopenharmony_ci	DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */
218562306a36Sopenharmony_ci		   QUIRK_FLAG_ALIGN_TRANSFER),
218662306a36Sopenharmony_ci	DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
218762306a36Sopenharmony_ci		   QUIRK_FLAG_ALIGN_TRANSFER),
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	/* Vendor matches */
219062306a36Sopenharmony_ci	VENDOR_FLG(0x045e, /* MS Lifecam */
219162306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
219262306a36Sopenharmony_ci	VENDOR_FLG(0x046d, /* Logitech */
219362306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY_1M),
219462306a36Sopenharmony_ci	VENDOR_FLG(0x047f, /* Plantronics */
219562306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY),
219662306a36Sopenharmony_ci	VENDOR_FLG(0x0644, /* TEAC Corp. */
219762306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY),
219862306a36Sopenharmony_ci	VENDOR_FLG(0x07fd, /* MOTU */
219962306a36Sopenharmony_ci		   QUIRK_FLAG_VALIDATE_RATES),
220062306a36Sopenharmony_ci	VENDOR_FLG(0x1235, /* Focusrite Novation */
220162306a36Sopenharmony_ci		   QUIRK_FLAG_VALIDATE_RATES),
220262306a36Sopenharmony_ci	VENDOR_FLG(0x1511, /* AURALiC */
220362306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
220462306a36Sopenharmony_ci	VENDOR_FLG(0x152a, /* Thesycon devices */
220562306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
220662306a36Sopenharmony_ci	VENDOR_FLG(0x18d1, /* iBasso devices */
220762306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
220862306a36Sopenharmony_ci	VENDOR_FLG(0x1de7, /* Phoenix Audio */
220962306a36Sopenharmony_ci		   QUIRK_FLAG_GET_SAMPLE_RATE),
221062306a36Sopenharmony_ci	VENDOR_FLG(0x20b1, /* XMOS based devices */
221162306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
221262306a36Sopenharmony_ci	VENDOR_FLG(0x21ed, /* Accuphase Laboratory */
221362306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
221462306a36Sopenharmony_ci	VENDOR_FLG(0x22d9, /* Oppo */
221562306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
221662306a36Sopenharmony_ci	VENDOR_FLG(0x23ba, /* Playback Design */
221762306a36Sopenharmony_ci		   QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY |
221862306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
221962306a36Sopenharmony_ci	VENDOR_FLG(0x25ce, /* Mytek devices */
222062306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
222162306a36Sopenharmony_ci	VENDOR_FLG(0x278b, /* Rotel? */
222262306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
222362306a36Sopenharmony_ci	VENDOR_FLG(0x292b, /* Gustard/Ess based devices */
222462306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
222562306a36Sopenharmony_ci	VENDOR_FLG(0x2972, /* FiiO devices */
222662306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
222762306a36Sopenharmony_ci	VENDOR_FLG(0x2ab6, /* T+A devices */
222862306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
222962306a36Sopenharmony_ci	VENDOR_FLG(0x2afd, /* McIntosh Laboratory, Inc. */
223062306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
223162306a36Sopenharmony_ci	VENDOR_FLG(0x2d87, /* Cayin device */
223262306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
223362306a36Sopenharmony_ci	VENDOR_FLG(0x3336, /* HEM devices */
223462306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
223562306a36Sopenharmony_ci	VENDOR_FLG(0x3353, /* Khadas devices */
223662306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
223762306a36Sopenharmony_ci	VENDOR_FLG(0x35f4, /* MSB Technology */
223862306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
223962306a36Sopenharmony_ci	VENDOR_FLG(0x3842, /* EVGA */
224062306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
224162306a36Sopenharmony_ci	VENDOR_FLG(0xc502, /* HiBy devices */
224262306a36Sopenharmony_ci		   QUIRK_FLAG_DSD_RAW),
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	{} /* terminator */
224562306a36Sopenharmony_ci};
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_civoid snd_usb_init_quirk_flags(struct snd_usb_audio *chip)
224862306a36Sopenharmony_ci{
224962306a36Sopenharmony_ci	const struct usb_audio_quirk_flags_table *p;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	for (p = quirk_flags_table; p->id; p++) {
225262306a36Sopenharmony_ci		if (chip->usb_id == p->id ||
225362306a36Sopenharmony_ci		    (!USB_ID_PRODUCT(p->id) &&
225462306a36Sopenharmony_ci		     USB_ID_VENDOR(chip->usb_id) == USB_ID_VENDOR(p->id))) {
225562306a36Sopenharmony_ci			usb_audio_dbg(chip,
225662306a36Sopenharmony_ci				      "Set quirk_flags 0x%x for device %04x:%04x\n",
225762306a36Sopenharmony_ci				      p->flags, USB_ID_VENDOR(chip->usb_id),
225862306a36Sopenharmony_ci				      USB_ID_PRODUCT(chip->usb_id));
225962306a36Sopenharmony_ci			chip->quirk_flags |= p->flags;
226062306a36Sopenharmony_ci			return;
226162306a36Sopenharmony_ci		}
226262306a36Sopenharmony_ci	}
226362306a36Sopenharmony_ci}
2264