xref: /kernel/linux/linux-5.10/sound/usb/quirks.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/init.h>
68c2ecf20Sopenharmony_ci#include <linux/slab.h>
78c2ecf20Sopenharmony_ci#include <linux/usb.h>
88c2ecf20Sopenharmony_ci#include <linux/usb/audio.h>
98c2ecf20Sopenharmony_ci#include <linux/usb/midi.h>
108c2ecf20Sopenharmony_ci#include <linux/bits.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <sound/control.h>
138c2ecf20Sopenharmony_ci#include <sound/core.h>
148c2ecf20Sopenharmony_ci#include <sound/info.h>
158c2ecf20Sopenharmony_ci#include <sound/pcm.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "usbaudio.h"
188c2ecf20Sopenharmony_ci#include "card.h"
198c2ecf20Sopenharmony_ci#include "mixer.h"
208c2ecf20Sopenharmony_ci#include "mixer_quirks.h"
218c2ecf20Sopenharmony_ci#include "midi.h"
228c2ecf20Sopenharmony_ci#include "quirks.h"
238c2ecf20Sopenharmony_ci#include "helper.h"
248c2ecf20Sopenharmony_ci#include "endpoint.h"
258c2ecf20Sopenharmony_ci#include "pcm.h"
268c2ecf20Sopenharmony_ci#include "clock.h"
278c2ecf20Sopenharmony_ci#include "stream.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * handle the quirks for the contained interfaces
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistatic int create_composite_quirk(struct snd_usb_audio *chip,
338c2ecf20Sopenharmony_ci				  struct usb_interface *iface,
348c2ecf20Sopenharmony_ci				  struct usb_driver *driver,
358c2ecf20Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk_comp)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
388c2ecf20Sopenharmony_ci	const struct snd_usb_audio_quirk *quirk;
398c2ecf20Sopenharmony_ci	int err;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
428c2ecf20Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
438c2ecf20Sopenharmony_ci		if (!iface)
448c2ecf20Sopenharmony_ci			continue;
458c2ecf20Sopenharmony_ci		if (quirk->ifnum != probed_ifnum &&
468c2ecf20Sopenharmony_ci		    usb_interface_claimed(iface))
478c2ecf20Sopenharmony_ci			continue;
488c2ecf20Sopenharmony_ci		err = snd_usb_create_quirk(chip, iface, driver, quirk);
498c2ecf20Sopenharmony_ci		if (err < 0)
508c2ecf20Sopenharmony_ci			return err;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
548c2ecf20Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
558c2ecf20Sopenharmony_ci		if (!iface)
568c2ecf20Sopenharmony_ci			continue;
578c2ecf20Sopenharmony_ci		if (quirk->ifnum != probed_ifnum &&
588c2ecf20Sopenharmony_ci		    !usb_interface_claimed(iface)) {
598c2ecf20Sopenharmony_ci			err = usb_driver_claim_interface(driver, iface,
608c2ecf20Sopenharmony_ci							 USB_AUDIO_IFACE_UNUSED);
618c2ecf20Sopenharmony_ci			if (err < 0)
628c2ecf20Sopenharmony_ci				return err;
638c2ecf20Sopenharmony_ci		}
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int ignore_interface_quirk(struct snd_usb_audio *chip,
708c2ecf20Sopenharmony_ci				  struct usb_interface *iface,
718c2ecf20Sopenharmony_ci				  struct usb_driver *driver,
728c2ecf20Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/*
798c2ecf20Sopenharmony_ci * Allow alignment on audio sub-slot (channel samples) rather than
808c2ecf20Sopenharmony_ci * on audio slots (audio frames)
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic int create_align_transfer_quirk(struct snd_usb_audio *chip,
838c2ecf20Sopenharmony_ci				       struct usb_interface *iface,
848c2ecf20Sopenharmony_ci				       struct usb_driver *driver,
858c2ecf20Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	chip->txfr_quirk = 1;
888c2ecf20Sopenharmony_ci	return 1;	/* Continue with creating streams and mixer */
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int create_any_midi_quirk(struct snd_usb_audio *chip,
928c2ecf20Sopenharmony_ci				 struct usb_interface *intf,
938c2ecf20Sopenharmony_ci				 struct usb_driver *driver,
948c2ecf20Sopenharmony_ci				 const struct snd_usb_audio_quirk *quirk)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci * create a stream for an interface with proper descriptors
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_cistatic int create_standard_audio_quirk(struct snd_usb_audio *chip,
1038c2ecf20Sopenharmony_ci				       struct usb_interface *iface,
1048c2ecf20Sopenharmony_ci				       struct usb_driver *driver,
1058c2ecf20Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct usb_host_interface *alts;
1088c2ecf20Sopenharmony_ci	struct usb_interface_descriptor *altsd;
1098c2ecf20Sopenharmony_ci	int err;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x1686, 0x00dd)) /* Zoom R16/24 */
1128c2ecf20Sopenharmony_ci		chip->tx_length_quirk = 1;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	alts = &iface->altsetting[0];
1158c2ecf20Sopenharmony_ci	altsd = get_iface_desc(alts);
1168c2ecf20Sopenharmony_ci	err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
1178c2ecf20Sopenharmony_ci	if (err < 0) {
1188c2ecf20Sopenharmony_ci		usb_audio_err(chip, "cannot setup if %d: error %d\n",
1198c2ecf20Sopenharmony_ci			   altsd->bInterfaceNumber, err);
1208c2ecf20Sopenharmony_ci		return err;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	/* reset the current interface */
1238c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0);
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * create a stream for an endpoint/altsetting without proper descriptors
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_cistatic int create_fixed_stream_quirk(struct snd_usb_audio *chip,
1318c2ecf20Sopenharmony_ci				     struct usb_interface *iface,
1328c2ecf20Sopenharmony_ci				     struct usb_driver *driver,
1338c2ecf20Sopenharmony_ci				     const struct snd_usb_audio_quirk *quirk)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct audioformat *fp;
1368c2ecf20Sopenharmony_ci	struct usb_host_interface *alts;
1378c2ecf20Sopenharmony_ci	struct usb_interface_descriptor *altsd;
1388c2ecf20Sopenharmony_ci	int stream, err;
1398c2ecf20Sopenharmony_ci	unsigned *rate_table = NULL;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
1428c2ecf20Sopenharmony_ci	if (!fp)
1438c2ecf20Sopenharmony_ci		return -ENOMEM;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fp->list);
1468c2ecf20Sopenharmony_ci	if (fp->nr_rates > MAX_NR_RATES) {
1478c2ecf20Sopenharmony_ci		kfree(fp);
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci	if (fp->nr_rates > 0) {
1518c2ecf20Sopenharmony_ci		rate_table = kmemdup(fp->rate_table,
1528c2ecf20Sopenharmony_ci				     sizeof(int) * fp->nr_rates, GFP_KERNEL);
1538c2ecf20Sopenharmony_ci		if (!rate_table) {
1548c2ecf20Sopenharmony_ci			kfree(fp);
1558c2ecf20Sopenharmony_ci			return -ENOMEM;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci		fp->rate_table = rate_table;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	stream = (fp->endpoint & USB_DIR_IN)
1618c2ecf20Sopenharmony_ci		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
1628c2ecf20Sopenharmony_ci	err = snd_usb_add_audio_stream(chip, stream, fp);
1638c2ecf20Sopenharmony_ci	if (err < 0)
1648c2ecf20Sopenharmony_ci		goto error;
1658c2ecf20Sopenharmony_ci	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
1668c2ecf20Sopenharmony_ci	    fp->altset_idx >= iface->num_altsetting) {
1678c2ecf20Sopenharmony_ci		err = -EINVAL;
1688c2ecf20Sopenharmony_ci		goto error;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	alts = &iface->altsetting[fp->altset_idx];
1718c2ecf20Sopenharmony_ci	altsd = get_iface_desc(alts);
1728c2ecf20Sopenharmony_ci	if (altsd->bNumEndpoints < 1) {
1738c2ecf20Sopenharmony_ci		err = -EINVAL;
1748c2ecf20Sopenharmony_ci		goto error;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	fp->protocol = altsd->bInterfaceProtocol;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (fp->datainterval == 0)
1808c2ecf20Sopenharmony_ci		fp->datainterval = snd_usb_parse_datainterval(chip, alts);
1818c2ecf20Sopenharmony_ci	if (fp->maxpacksize == 0)
1828c2ecf20Sopenharmony_ci		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
1838c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, fp->iface, 0);
1848c2ecf20Sopenharmony_ci	snd_usb_init_pitch(chip, fp->iface, alts, fp);
1858c2ecf20Sopenharmony_ci	snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max);
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci error:
1898c2ecf20Sopenharmony_ci	list_del(&fp->list); /* unlink for avoiding double-free */
1908c2ecf20Sopenharmony_ci	kfree(fp);
1918c2ecf20Sopenharmony_ci	kfree(rate_table);
1928c2ecf20Sopenharmony_ci	return err;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int create_auto_pcm_quirk(struct snd_usb_audio *chip,
1968c2ecf20Sopenharmony_ci				 struct usb_interface *iface,
1978c2ecf20Sopenharmony_ci				 struct usb_driver *driver)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct usb_host_interface *alts;
2008c2ecf20Sopenharmony_ci	struct usb_interface_descriptor *altsd;
2018c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *epd;
2028c2ecf20Sopenharmony_ci	struct uac1_as_header_descriptor *ashd;
2038c2ecf20Sopenharmony_ci	struct uac_format_type_i_discrete_descriptor *fmtd;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * Most Roland/Yamaha audio streaming interfaces have more or less
2078c2ecf20Sopenharmony_ci	 * standard descriptors, but older devices might lack descriptors, and
2088c2ecf20Sopenharmony_ci	 * future ones might change, so ensure that we fail silently if the
2098c2ecf20Sopenharmony_ci	 * interface doesn't look exactly right.
2108c2ecf20Sopenharmony_ci	 */
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* must have a non-zero altsetting for streaming */
2138c2ecf20Sopenharmony_ci	if (iface->num_altsetting < 2)
2148c2ecf20Sopenharmony_ci		return -ENODEV;
2158c2ecf20Sopenharmony_ci	alts = &iface->altsetting[1];
2168c2ecf20Sopenharmony_ci	altsd = get_iface_desc(alts);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* must have an isochronous endpoint for streaming */
2198c2ecf20Sopenharmony_ci	if (altsd->bNumEndpoints < 1)
2208c2ecf20Sopenharmony_ci		return -ENODEV;
2218c2ecf20Sopenharmony_ci	epd = get_endpoint(alts, 0);
2228c2ecf20Sopenharmony_ci	if (!usb_endpoint_xfer_isoc(epd))
2238c2ecf20Sopenharmony_ci		return -ENODEV;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/* must have format descriptors */
2268c2ecf20Sopenharmony_ci	ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
2278c2ecf20Sopenharmony_ci				       UAC_AS_GENERAL);
2288c2ecf20Sopenharmony_ci	fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
2298c2ecf20Sopenharmony_ci				       UAC_FORMAT_TYPE);
2308c2ecf20Sopenharmony_ci	if (!ashd || ashd->bLength < 7 ||
2318c2ecf20Sopenharmony_ci	    !fmtd || fmtd->bLength < 8)
2328c2ecf20Sopenharmony_ci		return -ENODEV;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return create_standard_audio_quirk(chip, iface, driver, NULL);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
2388c2ecf20Sopenharmony_ci				    struct usb_interface *iface,
2398c2ecf20Sopenharmony_ci				    struct usb_driver *driver,
2408c2ecf20Sopenharmony_ci				    struct usb_host_interface *alts)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
2438c2ecf20Sopenharmony_ci		.type = QUIRK_MIDI_YAMAHA
2448c2ecf20Sopenharmony_ci	};
2458c2ecf20Sopenharmony_ci	struct usb_midi_in_jack_descriptor *injd;
2468c2ecf20Sopenharmony_ci	struct usb_midi_out_jack_descriptor *outjd;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* must have some valid jack descriptors */
2498c2ecf20Sopenharmony_ci	injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
2508c2ecf20Sopenharmony_ci				       NULL, USB_MS_MIDI_IN_JACK);
2518c2ecf20Sopenharmony_ci	outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
2528c2ecf20Sopenharmony_ci					NULL, USB_MS_MIDI_OUT_JACK);
2538c2ecf20Sopenharmony_ci	if (!injd && !outjd)
2548c2ecf20Sopenharmony_ci		return -ENODEV;
2558c2ecf20Sopenharmony_ci	if ((injd && !snd_usb_validate_midi_desc(injd)) ||
2568c2ecf20Sopenharmony_ci	    (outjd && !snd_usb_validate_midi_desc(outjd)))
2578c2ecf20Sopenharmony_ci		return -ENODEV;
2588c2ecf20Sopenharmony_ci	if (injd && (injd->bLength < 5 ||
2598c2ecf20Sopenharmony_ci		     (injd->bJackType != USB_MS_EMBEDDED &&
2608c2ecf20Sopenharmony_ci		      injd->bJackType != USB_MS_EXTERNAL)))
2618c2ecf20Sopenharmony_ci		return -ENODEV;
2628c2ecf20Sopenharmony_ci	if (outjd && (outjd->bLength < 6 ||
2638c2ecf20Sopenharmony_ci		      (outjd->bJackType != USB_MS_EMBEDDED &&
2648c2ecf20Sopenharmony_ci		       outjd->bJackType != USB_MS_EXTERNAL)))
2658c2ecf20Sopenharmony_ci		return -ENODEV;
2668c2ecf20Sopenharmony_ci	return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic int create_roland_midi_quirk(struct snd_usb_audio *chip,
2708c2ecf20Sopenharmony_ci				    struct usb_interface *iface,
2718c2ecf20Sopenharmony_ci				    struct usb_driver *driver,
2728c2ecf20Sopenharmony_ci				    struct usb_host_interface *alts)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	static const struct snd_usb_audio_quirk roland_midi_quirk = {
2758c2ecf20Sopenharmony_ci		.type = QUIRK_MIDI_ROLAND
2768c2ecf20Sopenharmony_ci	};
2778c2ecf20Sopenharmony_ci	u8 *roland_desc = NULL;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* might have a vendor-specific descriptor <06 24 F1 02 ...> */
2808c2ecf20Sopenharmony_ci	for (;;) {
2818c2ecf20Sopenharmony_ci		roland_desc = snd_usb_find_csint_desc(alts->extra,
2828c2ecf20Sopenharmony_ci						      alts->extralen,
2838c2ecf20Sopenharmony_ci						      roland_desc, 0xf1);
2848c2ecf20Sopenharmony_ci		if (!roland_desc)
2858c2ecf20Sopenharmony_ci			return -ENODEV;
2868c2ecf20Sopenharmony_ci		if (roland_desc[0] < 6 || roland_desc[3] != 2)
2878c2ecf20Sopenharmony_ci			continue;
2888c2ecf20Sopenharmony_ci		return create_any_midi_quirk(chip, iface, driver,
2898c2ecf20Sopenharmony_ci					     &roland_midi_quirk);
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int create_std_midi_quirk(struct snd_usb_audio *chip,
2948c2ecf20Sopenharmony_ci				 struct usb_interface *iface,
2958c2ecf20Sopenharmony_ci				 struct usb_driver *driver,
2968c2ecf20Sopenharmony_ci				 struct usb_host_interface *alts)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct usb_ms_header_descriptor *mshd;
2998c2ecf20Sopenharmony_ci	struct usb_ms_endpoint_descriptor *msepd;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* must have the MIDIStreaming interface header descriptor*/
3028c2ecf20Sopenharmony_ci	mshd = (struct usb_ms_header_descriptor *)alts->extra;
3038c2ecf20Sopenharmony_ci	if (alts->extralen < 7 ||
3048c2ecf20Sopenharmony_ci	    mshd->bLength < 7 ||
3058c2ecf20Sopenharmony_ci	    mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
3068c2ecf20Sopenharmony_ci	    mshd->bDescriptorSubtype != USB_MS_HEADER)
3078c2ecf20Sopenharmony_ci		return -ENODEV;
3088c2ecf20Sopenharmony_ci	/* must have the MIDIStreaming endpoint descriptor*/
3098c2ecf20Sopenharmony_ci	msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
3108c2ecf20Sopenharmony_ci	if (alts->endpoint[0].extralen < 4 ||
3118c2ecf20Sopenharmony_ci	    msepd->bLength < 4 ||
3128c2ecf20Sopenharmony_ci	    msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
3138c2ecf20Sopenharmony_ci	    msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
3148c2ecf20Sopenharmony_ci	    msepd->bNumEmbMIDIJack < 1 ||
3158c2ecf20Sopenharmony_ci	    msepd->bNumEmbMIDIJack > 16)
3168c2ecf20Sopenharmony_ci		return -ENODEV;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return create_any_midi_quirk(chip, iface, driver, NULL);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int create_auto_midi_quirk(struct snd_usb_audio *chip,
3228c2ecf20Sopenharmony_ci				  struct usb_interface *iface,
3238c2ecf20Sopenharmony_ci				  struct usb_driver *driver)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct usb_host_interface *alts;
3268c2ecf20Sopenharmony_ci	struct usb_interface_descriptor *altsd;
3278c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *epd;
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	alts = &iface->altsetting[0];
3318c2ecf20Sopenharmony_ci	altsd = get_iface_desc(alts);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* must have at least one bulk/interrupt endpoint for streaming */
3348c2ecf20Sopenharmony_ci	if (altsd->bNumEndpoints < 1)
3358c2ecf20Sopenharmony_ci		return -ENODEV;
3368c2ecf20Sopenharmony_ci	epd = get_endpoint(alts, 0);
3378c2ecf20Sopenharmony_ci	if (!usb_endpoint_xfer_bulk(epd) &&
3388c2ecf20Sopenharmony_ci	    !usb_endpoint_xfer_int(epd))
3398c2ecf20Sopenharmony_ci		return -ENODEV;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	switch (USB_ID_VENDOR(chip->usb_id)) {
3428c2ecf20Sopenharmony_ci	case 0x0499: /* Yamaha */
3438c2ecf20Sopenharmony_ci		err = create_yamaha_midi_quirk(chip, iface, driver, alts);
3448c2ecf20Sopenharmony_ci		if (err != -ENODEV)
3458c2ecf20Sopenharmony_ci			return err;
3468c2ecf20Sopenharmony_ci		break;
3478c2ecf20Sopenharmony_ci	case 0x0582: /* Roland */
3488c2ecf20Sopenharmony_ci		err = create_roland_midi_quirk(chip, iface, driver, alts);
3498c2ecf20Sopenharmony_ci		if (err != -ENODEV)
3508c2ecf20Sopenharmony_ci			return err;
3518c2ecf20Sopenharmony_ci		break;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return create_std_midi_quirk(chip, iface, driver, alts);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic int create_autodetect_quirk(struct snd_usb_audio *chip,
3588c2ecf20Sopenharmony_ci				   struct usb_interface *iface,
3598c2ecf20Sopenharmony_ci				   struct usb_driver *driver)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	int err;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	err = create_auto_pcm_quirk(chip, iface, driver);
3648c2ecf20Sopenharmony_ci	if (err == -ENODEV)
3658c2ecf20Sopenharmony_ci		err = create_auto_midi_quirk(chip, iface, driver);
3668c2ecf20Sopenharmony_ci	return err;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int create_autodetect_quirks(struct snd_usb_audio *chip,
3708c2ecf20Sopenharmony_ci				    struct usb_interface *iface,
3718c2ecf20Sopenharmony_ci				    struct usb_driver *driver,
3728c2ecf20Sopenharmony_ci				    const struct snd_usb_audio_quirk *quirk)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
3758c2ecf20Sopenharmony_ci	int ifcount, ifnum, err;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	err = create_autodetect_quirk(chip, iface, driver);
3788c2ecf20Sopenharmony_ci	if (err < 0)
3798c2ecf20Sopenharmony_ci		return err;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/*
3828c2ecf20Sopenharmony_ci	 * ALSA PCM playback/capture devices cannot be registered in two steps,
3838c2ecf20Sopenharmony_ci	 * so we have to claim the other corresponding interface here.
3848c2ecf20Sopenharmony_ci	 */
3858c2ecf20Sopenharmony_ci	ifcount = chip->dev->actconfig->desc.bNumInterfaces;
3868c2ecf20Sopenharmony_ci	for (ifnum = 0; ifnum < ifcount; ifnum++) {
3878c2ecf20Sopenharmony_ci		if (ifnum == probed_ifnum || quirk->ifnum >= 0)
3888c2ecf20Sopenharmony_ci			continue;
3898c2ecf20Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, ifnum);
3908c2ecf20Sopenharmony_ci		if (!iface ||
3918c2ecf20Sopenharmony_ci		    usb_interface_claimed(iface) ||
3928c2ecf20Sopenharmony_ci		    get_iface_desc(iface->altsetting)->bInterfaceClass !=
3938c2ecf20Sopenharmony_ci							USB_CLASS_VENDOR_SPEC)
3948c2ecf20Sopenharmony_ci			continue;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		err = create_autodetect_quirk(chip, iface, driver);
3978c2ecf20Sopenharmony_ci		if (err >= 0) {
3988c2ecf20Sopenharmony_ci			err = usb_driver_claim_interface(driver, iface,
3998c2ecf20Sopenharmony_ci							 USB_AUDIO_IFACE_UNUSED);
4008c2ecf20Sopenharmony_ci			if (err < 0)
4018c2ecf20Sopenharmony_ci				return err;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return 0;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/*
4098c2ecf20Sopenharmony_ci * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
4108c2ecf20Sopenharmony_ci * The only way to detect the sample rate is by looking at wMaxPacketSize.
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic int create_uaxx_quirk(struct snd_usb_audio *chip,
4138c2ecf20Sopenharmony_ci			     struct usb_interface *iface,
4148c2ecf20Sopenharmony_ci			     struct usb_driver *driver,
4158c2ecf20Sopenharmony_ci			     const struct snd_usb_audio_quirk *quirk)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	static const struct audioformat ua_format = {
4188c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S24_3LE,
4198c2ecf20Sopenharmony_ci		.channels = 2,
4208c2ecf20Sopenharmony_ci		.fmt_type = UAC_FORMAT_TYPE_I,
4218c2ecf20Sopenharmony_ci		.altsetting = 1,
4228c2ecf20Sopenharmony_ci		.altset_idx = 1,
4238c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_CONTINUOUS,
4248c2ecf20Sopenharmony_ci	};
4258c2ecf20Sopenharmony_ci	struct usb_host_interface *alts;
4268c2ecf20Sopenharmony_ci	struct usb_interface_descriptor *altsd;
4278c2ecf20Sopenharmony_ci	struct audioformat *fp;
4288c2ecf20Sopenharmony_ci	int stream, err;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* both PCM and MIDI interfaces have 2 or more altsettings */
4318c2ecf20Sopenharmony_ci	if (iface->num_altsetting < 2)
4328c2ecf20Sopenharmony_ci		return -ENXIO;
4338c2ecf20Sopenharmony_ci	alts = &iface->altsetting[1];
4348c2ecf20Sopenharmony_ci	altsd = get_iface_desc(alts);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (altsd->bNumEndpoints == 2) {
4378c2ecf20Sopenharmony_ci		static const struct snd_usb_midi_endpoint_info ua700_ep = {
4388c2ecf20Sopenharmony_ci			.out_cables = 0x0003,
4398c2ecf20Sopenharmony_ci			.in_cables  = 0x0003
4408c2ecf20Sopenharmony_ci		};
4418c2ecf20Sopenharmony_ci		static const struct snd_usb_audio_quirk ua700_quirk = {
4428c2ecf20Sopenharmony_ci			.type = QUIRK_MIDI_FIXED_ENDPOINT,
4438c2ecf20Sopenharmony_ci			.data = &ua700_ep
4448c2ecf20Sopenharmony_ci		};
4458c2ecf20Sopenharmony_ci		static const struct snd_usb_midi_endpoint_info uaxx_ep = {
4468c2ecf20Sopenharmony_ci			.out_cables = 0x0001,
4478c2ecf20Sopenharmony_ci			.in_cables  = 0x0001
4488c2ecf20Sopenharmony_ci		};
4498c2ecf20Sopenharmony_ci		static const struct snd_usb_audio_quirk uaxx_quirk = {
4508c2ecf20Sopenharmony_ci			.type = QUIRK_MIDI_FIXED_ENDPOINT,
4518c2ecf20Sopenharmony_ci			.data = &uaxx_ep
4528c2ecf20Sopenharmony_ci		};
4538c2ecf20Sopenharmony_ci		const struct snd_usb_audio_quirk *quirk =
4548c2ecf20Sopenharmony_ci			chip->usb_id == USB_ID(0x0582, 0x002b)
4558c2ecf20Sopenharmony_ci			? &ua700_quirk : &uaxx_quirk;
4568c2ecf20Sopenharmony_ci		return __snd_usbmidi_create(chip->card, iface,
4578c2ecf20Sopenharmony_ci					  &chip->midi_list, quirk,
4588c2ecf20Sopenharmony_ci					  chip->usb_id);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (altsd->bNumEndpoints != 1)
4628c2ecf20Sopenharmony_ci		return -ENXIO;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	fp = kmemdup(&ua_format, sizeof(*fp), GFP_KERNEL);
4658c2ecf20Sopenharmony_ci	if (!fp)
4668c2ecf20Sopenharmony_ci		return -ENOMEM;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	fp->iface = altsd->bInterfaceNumber;
4698c2ecf20Sopenharmony_ci	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
4708c2ecf20Sopenharmony_ci	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
4718c2ecf20Sopenharmony_ci	fp->datainterval = 0;
4728c2ecf20Sopenharmony_ci	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
4738c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fp->list);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	switch (fp->maxpacksize) {
4768c2ecf20Sopenharmony_ci	case 0x120:
4778c2ecf20Sopenharmony_ci		fp->rate_max = fp->rate_min = 44100;
4788c2ecf20Sopenharmony_ci		break;
4798c2ecf20Sopenharmony_ci	case 0x138:
4808c2ecf20Sopenharmony_ci	case 0x140:
4818c2ecf20Sopenharmony_ci		fp->rate_max = fp->rate_min = 48000;
4828c2ecf20Sopenharmony_ci		break;
4838c2ecf20Sopenharmony_ci	case 0x258:
4848c2ecf20Sopenharmony_ci	case 0x260:
4858c2ecf20Sopenharmony_ci		fp->rate_max = fp->rate_min = 96000;
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci	default:
4888c2ecf20Sopenharmony_ci		usb_audio_err(chip, "unknown sample rate\n");
4898c2ecf20Sopenharmony_ci		kfree(fp);
4908c2ecf20Sopenharmony_ci		return -ENXIO;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	stream = (fp->endpoint & USB_DIR_IN)
4948c2ecf20Sopenharmony_ci		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
4958c2ecf20Sopenharmony_ci	err = snd_usb_add_audio_stream(chip, stream, fp);
4968c2ecf20Sopenharmony_ci	if (err < 0) {
4978c2ecf20Sopenharmony_ci		list_del(&fp->list); /* unlink for avoiding double-free */
4988c2ecf20Sopenharmony_ci		kfree(fp);
4998c2ecf20Sopenharmony_ci		return err;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, fp->iface, 0);
5028c2ecf20Sopenharmony_ci	return 0;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci/*
5068c2ecf20Sopenharmony_ci * Create a standard mixer for the specified interface.
5078c2ecf20Sopenharmony_ci */
5088c2ecf20Sopenharmony_cistatic int create_standard_mixer_quirk(struct snd_usb_audio *chip,
5098c2ecf20Sopenharmony_ci				       struct usb_interface *iface,
5108c2ecf20Sopenharmony_ci				       struct usb_driver *driver,
5118c2ecf20Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	if (quirk->ifnum < 0)
5148c2ecf20Sopenharmony_ci		return 0;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return snd_usb_create_mixer(chip, quirk->ifnum, 0);
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip,
5218c2ecf20Sopenharmony_ci				       struct usb_interface *iface,
5228c2ecf20Sopenharmony_ci				       struct usb_driver *driver,
5238c2ecf20Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	chip->setup_fmt_after_resume_quirk = 1;
5268c2ecf20Sopenharmony_ci	return 1;	/* Continue with creating streams and mixer */
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int setup_disable_autosuspend(struct snd_usb_audio *chip,
5308c2ecf20Sopenharmony_ci				       struct usb_interface *iface,
5318c2ecf20Sopenharmony_ci				       struct usb_driver *driver,
5328c2ecf20Sopenharmony_ci				       const struct snd_usb_audio_quirk *quirk)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	usb_disable_autosuspend(interface_to_usbdev(iface));
5358c2ecf20Sopenharmony_ci	return 1;	/* Continue with creating streams and mixer */
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/*
5398c2ecf20Sopenharmony_ci * audio-interface quirks
5408c2ecf20Sopenharmony_ci *
5418c2ecf20Sopenharmony_ci * returns zero if no standard audio/MIDI parsing is needed.
5428c2ecf20Sopenharmony_ci * returns a positive value if standard audio/midi interfaces are parsed
5438c2ecf20Sopenharmony_ci * after this.
5448c2ecf20Sopenharmony_ci * returns a negative value at error.
5458c2ecf20Sopenharmony_ci */
5468c2ecf20Sopenharmony_ciint snd_usb_create_quirk(struct snd_usb_audio *chip,
5478c2ecf20Sopenharmony_ci			 struct usb_interface *iface,
5488c2ecf20Sopenharmony_ci			 struct usb_driver *driver,
5498c2ecf20Sopenharmony_ci			 const struct snd_usb_audio_quirk *quirk)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	typedef int (*quirk_func_t)(struct snd_usb_audio *,
5528c2ecf20Sopenharmony_ci				    struct usb_interface *,
5538c2ecf20Sopenharmony_ci				    struct usb_driver *,
5548c2ecf20Sopenharmony_ci				    const struct snd_usb_audio_quirk *);
5558c2ecf20Sopenharmony_ci	static const quirk_func_t quirk_funcs[] = {
5568c2ecf20Sopenharmony_ci		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
5578c2ecf20Sopenharmony_ci		[QUIRK_COMPOSITE] = create_composite_quirk,
5588c2ecf20Sopenharmony_ci		[QUIRK_AUTODETECT] = create_autodetect_quirks,
5598c2ecf20Sopenharmony_ci		[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
5608c2ecf20Sopenharmony_ci		[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
5618c2ecf20Sopenharmony_ci		[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
5628c2ecf20Sopenharmony_ci		[QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
5638c2ecf20Sopenharmony_ci		[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
5648c2ecf20Sopenharmony_ci		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
5658c2ecf20Sopenharmony_ci		[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
5668c2ecf20Sopenharmony_ci		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
5678c2ecf20Sopenharmony_ci		[QUIRK_MIDI_CME] = create_any_midi_quirk,
5688c2ecf20Sopenharmony_ci		[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
5698c2ecf20Sopenharmony_ci		[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
5708c2ecf20Sopenharmony_ci		[QUIRK_MIDI_CH345] = create_any_midi_quirk,
5718c2ecf20Sopenharmony_ci		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
5728c2ecf20Sopenharmony_ci		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
5738c2ecf20Sopenharmony_ci		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
5748c2ecf20Sopenharmony_ci		[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
5758c2ecf20Sopenharmony_ci		[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
5768c2ecf20Sopenharmony_ci		[QUIRK_SETUP_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk,
5778c2ecf20Sopenharmony_ci		[QUIRK_SETUP_DISABLE_AUTOSUSPEND] = setup_disable_autosuspend,
5788c2ecf20Sopenharmony_ci	};
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (quirk->type < QUIRK_TYPE_COUNT) {
5818c2ecf20Sopenharmony_ci		return quirk_funcs[quirk->type](chip, iface, driver, quirk);
5828c2ecf20Sopenharmony_ci	} else {
5838c2ecf20Sopenharmony_ci		usb_audio_err(chip, "invalid quirk type %d\n", quirk->type);
5848c2ecf20Sopenharmony_ci		return -ENXIO;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci/*
5898c2ecf20Sopenharmony_ci * boot quirks
5908c2ecf20Sopenharmony_ci */
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci#define EXTIGY_FIRMWARE_SIZE_OLD 794
5938c2ecf20Sopenharmony_ci#define EXTIGY_FIRMWARE_SIZE_NEW 483
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	struct usb_host_config *config = dev->actconfig;
5988c2ecf20Sopenharmony_ci	int err;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
6018c2ecf20Sopenharmony_ci	    le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
6028c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "sending Extigy boot sequence...\n");
6038c2ecf20Sopenharmony_ci		/* Send message to force it to reconnect with full interface. */
6048c2ecf20Sopenharmony_ci		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
6058c2ecf20Sopenharmony_ci				      0x10, 0x43, 0x0001, 0x000a, NULL, 0);
6068c2ecf20Sopenharmony_ci		if (err < 0)
6078c2ecf20Sopenharmony_ci			dev_dbg(&dev->dev, "error sending boot message: %d\n", err);
6088c2ecf20Sopenharmony_ci		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
6098c2ecf20Sopenharmony_ci				&dev->descriptor, sizeof(dev->descriptor));
6108c2ecf20Sopenharmony_ci		config = dev->actconfig;
6118c2ecf20Sopenharmony_ci		if (err < 0)
6128c2ecf20Sopenharmony_ci			dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
6138c2ecf20Sopenharmony_ci		err = usb_reset_configuration(dev);
6148c2ecf20Sopenharmony_ci		if (err < 0)
6158c2ecf20Sopenharmony_ci			dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
6168c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "extigy_boot: new boot length = %d\n",
6178c2ecf20Sopenharmony_ci			    le16_to_cpu(get_cfg_desc(config)->wTotalLength));
6188c2ecf20Sopenharmony_ci		return -ENODEV; /* quit this anyway */
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci	return 0;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	u8 buf = 1;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
6288c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
6298c2ecf20Sopenharmony_ci			0, 0, &buf, 1);
6308c2ecf20Sopenharmony_ci	if (buf == 0) {
6318c2ecf20Sopenharmony_ci		snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
6328c2ecf20Sopenharmony_ci				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
6338c2ecf20Sopenharmony_ci				1, 2000, NULL, 0);
6348c2ecf20Sopenharmony_ci		return -ENODEV;
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci	return 0;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	int err;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (dev->actconfig->desc.bConfigurationValue == 1) {
6448c2ecf20Sopenharmony_ci		dev_info(&dev->dev,
6458c2ecf20Sopenharmony_ci			   "Fast Track Pro switching to config #2\n");
6468c2ecf20Sopenharmony_ci		/* This function has to be available by the usb core module.
6478c2ecf20Sopenharmony_ci		 * if it is not avialable the boot quirk has to be left out
6488c2ecf20Sopenharmony_ci		 * and the configuration has to be set by udev or hotplug
6498c2ecf20Sopenharmony_ci		 * rules
6508c2ecf20Sopenharmony_ci		 */
6518c2ecf20Sopenharmony_ci		err = usb_driver_set_configuration(dev, 2);
6528c2ecf20Sopenharmony_ci		if (err < 0)
6538c2ecf20Sopenharmony_ci			dev_dbg(&dev->dev,
6548c2ecf20Sopenharmony_ci				"error usb_driver_set_configuration: %d\n",
6558c2ecf20Sopenharmony_ci				err);
6568c2ecf20Sopenharmony_ci		/* Always return an error, so that we stop creating a device
6578c2ecf20Sopenharmony_ci		   that will just be destroyed and recreated with a new
6588c2ecf20Sopenharmony_ci		   configuration */
6598c2ecf20Sopenharmony_ci		return -ENODEV;
6608c2ecf20Sopenharmony_ci	} else
6618c2ecf20Sopenharmony_ci		dev_info(&dev->dev, "Fast Track Pro config OK\n");
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return 0;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci/*
6678c2ecf20Sopenharmony_ci * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
6688c2ecf20Sopenharmony_ci * documented in the device's data sheet.
6698c2ecf20Sopenharmony_ci */
6708c2ecf20Sopenharmony_cistatic int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	u8 buf[4];
6738c2ecf20Sopenharmony_ci	buf[0] = 0x20;
6748c2ecf20Sopenharmony_ci	buf[1] = value & 0xff;
6758c2ecf20Sopenharmony_ci	buf[2] = (value >> 8) & 0xff;
6768c2ecf20Sopenharmony_ci	buf[3] = reg;
6778c2ecf20Sopenharmony_ci	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
6788c2ecf20Sopenharmony_ci			       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
6798c2ecf20Sopenharmony_ci			       0, 0, &buf, 4);
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int snd_usb_cm106_boot_quirk(struct usb_device *dev)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	/*
6858c2ecf20Sopenharmony_ci	 * Enable line-out driver mode, set headphone source to front
6868c2ecf20Sopenharmony_ci	 * channels, enable stereo mic.
6878c2ecf20Sopenharmony_ci	 */
6888c2ecf20Sopenharmony_ci	return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci/*
6928c2ecf20Sopenharmony_ci * CM6206 registers from the CM6206 datasheet rev 2.1
6938c2ecf20Sopenharmony_ci */
6948c2ecf20Sopenharmony_ci#define CM6206_REG0_DMA_MASTER BIT(15)
6958c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_RATE_48K (2 << 12)
6968c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_RATE_96K (7 << 12)
6978c2ecf20Sopenharmony_ci/* Bit 4 thru 11 is the S/PDIF category code */
6988c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_CAT_CODE_GENERAL (0 << 4)
6998c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_EMPHASIS_CD BIT(3)
7008c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_COPYRIGHT_NA BIT(2)
7018c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_NON_AUDIO BIT(1)
7028c2ecf20Sopenharmony_ci#define CM6206_REG0_SPDIFO_PRO_FORMAT BIT(0)
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci#define CM6206_REG1_TEST_SEL_CLK BIT(14)
7058c2ecf20Sopenharmony_ci#define CM6206_REG1_PLLBIN_EN BIT(13)
7068c2ecf20Sopenharmony_ci#define CM6206_REG1_SOFT_MUTE_EN BIT(12)
7078c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO4_OUT BIT(11)
7088c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO4_OE BIT(10)
7098c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO3_OUT BIT(9)
7108c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO3_OE BIT(8)
7118c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO2_OUT BIT(7)
7128c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO2_OE BIT(6)
7138c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO1_OUT BIT(5)
7148c2ecf20Sopenharmony_ci#define CM6206_REG1_GPIO1_OE BIT(4)
7158c2ecf20Sopenharmony_ci#define CM6206_REG1_SPDIFO_INVALID BIT(3)
7168c2ecf20Sopenharmony_ci#define CM6206_REG1_SPDIF_LOOP_EN BIT(2)
7178c2ecf20Sopenharmony_ci#define CM6206_REG1_SPDIFO_DIS BIT(1)
7188c2ecf20Sopenharmony_ci#define CM6206_REG1_SPDIFI_MIX BIT(0)
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci#define CM6206_REG2_DRIVER_ON BIT(15)
7218c2ecf20Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_SIDE_CHANNELS (0 << 13)
7228c2ecf20Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_SURROUND_CHANNELS (1 << 13)
7238c2ecf20Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_CENTER_SUBW (2 << 13)
7248c2ecf20Sopenharmony_ci#define CM6206_REG2_HEADP_SEL_FRONT_CHANNELS (3 << 13)
7258c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_HEADPHONE_RIGHT BIT(12)
7268c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_HEADPHONE_LEFT BIT(11)
7278c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_REAR_SURROUND_RIGHT BIT(10)
7288c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_REAR_SURROUND_LEFT BIT(9)
7298c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_SIDE_SURROUND_RIGHT BIT(8)
7308c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_SIDE_SURROUND_LEFT BIT(7)
7318c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_SUBWOOFER BIT(6)
7328c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_CENTER BIT(5)
7338c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_RIGHT_FRONT BIT(3)
7348c2ecf20Sopenharmony_ci#define CM6206_REG2_MUTE_LEFT_FRONT BIT(3)
7358c2ecf20Sopenharmony_ci#define CM6206_REG2_EN_BTL BIT(2)
7368c2ecf20Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_1_5_MHZ (0)
7378c2ecf20Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_3_MHZ (1)
7388c2ecf20Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_6_MHZ (2)
7398c2ecf20Sopenharmony_ci#define CM6206_REG2_MCUCLKSEL_12_MHZ (3)
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci/* Bit 11..13 sets the sensitivity to FLY tuner volume control VP/VD signal */
7428c2ecf20Sopenharmony_ci#define CM6206_REG3_FLYSPEED_DEFAULT (2 << 11)
7438c2ecf20Sopenharmony_ci#define CM6206_REG3_VRAP25EN BIT(10)
7448c2ecf20Sopenharmony_ci#define CM6206_REG3_MSEL1 BIT(9)
7458c2ecf20Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_44_1K BIT(0 << 7)
7468c2ecf20Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_48K BIT(2 << 7)
7478c2ecf20Sopenharmony_ci#define CM6206_REG3_SPDIFI_RATE_32K BIT(3 << 7)
7488c2ecf20Sopenharmony_ci#define CM6206_REG3_PINSEL BIT(6)
7498c2ecf20Sopenharmony_ci#define CM6206_REG3_FOE BIT(5)
7508c2ecf20Sopenharmony_ci#define CM6206_REG3_ROE BIT(4)
7518c2ecf20Sopenharmony_ci#define CM6206_REG3_CBOE BIT(3)
7528c2ecf20Sopenharmony_ci#define CM6206_REG3_LOSE BIT(2)
7538c2ecf20Sopenharmony_ci#define CM6206_REG3_HPOE BIT(1)
7548c2ecf20Sopenharmony_ci#define CM6206_REG3_SPDIFI_CANREC BIT(0)
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci#define CM6206_REG5_DA_RSTN BIT(13)
7578c2ecf20Sopenharmony_ci#define CM6206_REG5_AD_RSTN BIT(12)
7588c2ecf20Sopenharmony_ci#define CM6206_REG5_SPDIFO_AD2SPDO BIT(12)
7598c2ecf20Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_FRONT (0 << 9)
7608c2ecf20Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_SIDE_SUR (1 << 9)
7618c2ecf20Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_CEN_LFE (2 << 9)
7628c2ecf20Sopenharmony_ci#define CM6206_REG5_SPDIFO_SEL_REAR_SUR (3 << 9)
7638c2ecf20Sopenharmony_ci#define CM6206_REG5_CODECM BIT(8)
7648c2ecf20Sopenharmony_ci#define CM6206_REG5_EN_HPF BIT(7)
7658c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA4 BIT(6)
7668c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA3 BIT(5)
7678c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA2 BIT(4)
7688c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDA1 BIT(3)
7698c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_NORMAL 0
7708c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_FRONT 4
7718c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_S_SURROUND 5
7728c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_CEN_LFE 6
7738c2ecf20Sopenharmony_ci#define CM6206_REG5_T_SEL_DSDAD_R_SURROUND 7
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	int err  = 0, reg;
7788c2ecf20Sopenharmony_ci	int val[] = {
7798c2ecf20Sopenharmony_ci		/*
7808c2ecf20Sopenharmony_ci		 * Values here are chosen based on sniffing USB traffic
7818c2ecf20Sopenharmony_ci		 * under Windows.
7828c2ecf20Sopenharmony_ci		 *
7838c2ecf20Sopenharmony_ci		 * REG0: DAC is master, sample rate 48kHz, no copyright
7848c2ecf20Sopenharmony_ci		 */
7858c2ecf20Sopenharmony_ci		CM6206_REG0_SPDIFO_RATE_48K |
7868c2ecf20Sopenharmony_ci		CM6206_REG0_SPDIFO_COPYRIGHT_NA,
7878c2ecf20Sopenharmony_ci		/*
7888c2ecf20Sopenharmony_ci		 * REG1: PLL binary search enable, soft mute enable.
7898c2ecf20Sopenharmony_ci		 */
7908c2ecf20Sopenharmony_ci		CM6206_REG1_PLLBIN_EN |
7918c2ecf20Sopenharmony_ci		CM6206_REG1_SOFT_MUTE_EN,
7928c2ecf20Sopenharmony_ci		/*
7938c2ecf20Sopenharmony_ci		 * REG2: enable output drivers,
7948c2ecf20Sopenharmony_ci		 * select front channels to the headphone output,
7958c2ecf20Sopenharmony_ci		 * then mute the headphone channels, run the MCU
7968c2ecf20Sopenharmony_ci		 * at 1.5 MHz.
7978c2ecf20Sopenharmony_ci		 */
7988c2ecf20Sopenharmony_ci		CM6206_REG2_DRIVER_ON |
7998c2ecf20Sopenharmony_ci		CM6206_REG2_HEADP_SEL_FRONT_CHANNELS |
8008c2ecf20Sopenharmony_ci		CM6206_REG2_MUTE_HEADPHONE_RIGHT |
8018c2ecf20Sopenharmony_ci		CM6206_REG2_MUTE_HEADPHONE_LEFT,
8028c2ecf20Sopenharmony_ci		/*
8038c2ecf20Sopenharmony_ci		 * REG3: default flyspeed, set 2.5V mic bias
8048c2ecf20Sopenharmony_ci		 * enable all line out ports and enable SPDIF
8058c2ecf20Sopenharmony_ci		 */
8068c2ecf20Sopenharmony_ci		CM6206_REG3_FLYSPEED_DEFAULT |
8078c2ecf20Sopenharmony_ci		CM6206_REG3_VRAP25EN |
8088c2ecf20Sopenharmony_ci		CM6206_REG3_FOE |
8098c2ecf20Sopenharmony_ci		CM6206_REG3_ROE |
8108c2ecf20Sopenharmony_ci		CM6206_REG3_CBOE |
8118c2ecf20Sopenharmony_ci		CM6206_REG3_LOSE |
8128c2ecf20Sopenharmony_ci		CM6206_REG3_HPOE |
8138c2ecf20Sopenharmony_ci		CM6206_REG3_SPDIFI_CANREC,
8148c2ecf20Sopenharmony_ci		/* REG4 is just a bunch of GPIO lines */
8158c2ecf20Sopenharmony_ci		0x0000,
8168c2ecf20Sopenharmony_ci		/* REG5: de-assert AD/DA reset signals */
8178c2ecf20Sopenharmony_ci		CM6206_REG5_DA_RSTN |
8188c2ecf20Sopenharmony_ci		CM6206_REG5_AD_RSTN };
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
8218c2ecf20Sopenharmony_ci		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
8228c2ecf20Sopenharmony_ci		if (err < 0)
8238c2ecf20Sopenharmony_ci			return err;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return err;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci/* quirk for Plantronics GameCom 780 with CM6302 chip */
8308c2ecf20Sopenharmony_cistatic int snd_usb_gamecon780_boot_quirk(struct usb_device *dev)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	/* set the initial volume and don't change; other values are either
8338c2ecf20Sopenharmony_ci	 * too loud or silent due to firmware bug (bko#65251)
8348c2ecf20Sopenharmony_ci	 */
8358c2ecf20Sopenharmony_ci	u8 buf[2] = { 0x74, 0xe3 };
8368c2ecf20Sopenharmony_ci	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
8378c2ecf20Sopenharmony_ci			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
8388c2ecf20Sopenharmony_ci			UAC_FU_VOLUME << 8, 9 << 8, buf, 2);
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci/*
8428c2ecf20Sopenharmony_ci * Novation Twitch DJ controller
8438c2ecf20Sopenharmony_ci * Focusrite Novation Saffire 6 USB audio card
8448c2ecf20Sopenharmony_ci */
8458c2ecf20Sopenharmony_cistatic int snd_usb_novation_boot_quirk(struct usb_device *dev)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	/* preemptively set up the device because otherwise the
8488c2ecf20Sopenharmony_ci	 * raw MIDI endpoints are not active */
8498c2ecf20Sopenharmony_ci	usb_set_interface(dev, 0, 1);
8508c2ecf20Sopenharmony_ci	return 0;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci/*
8548c2ecf20Sopenharmony_ci * This call will put the synth in "USB send" mode, i.e it will send MIDI
8558c2ecf20Sopenharmony_ci * messages through USB (this is disabled at startup). The synth will
8568c2ecf20Sopenharmony_ci * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
8578c2ecf20Sopenharmony_ci * sign on its LCD. Values here are chosen based on sniffing USB traffic
8588c2ecf20Sopenharmony_ci * under Windows.
8598c2ecf20Sopenharmony_ci */
8608c2ecf20Sopenharmony_cistatic int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	int err, actual_length;
8638c2ecf20Sopenharmony_ci	/* "midi send" enable */
8648c2ecf20Sopenharmony_ci	static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
8658c2ecf20Sopenharmony_ci	void *buf;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x05)))
8688c2ecf20Sopenharmony_ci		return -EINVAL;
8698c2ecf20Sopenharmony_ci	buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
8708c2ecf20Sopenharmony_ci	if (!buf)
8718c2ecf20Sopenharmony_ci		return -ENOMEM;
8728c2ecf20Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
8738c2ecf20Sopenharmony_ci			ARRAY_SIZE(seq), &actual_length, 1000);
8748c2ecf20Sopenharmony_ci	kfree(buf);
8758c2ecf20Sopenharmony_ci	if (err < 0)
8768c2ecf20Sopenharmony_ci		return err;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return 0;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci/*
8828c2ecf20Sopenharmony_ci * Some sound cards from Native Instruments are in fact compliant to the USB
8838c2ecf20Sopenharmony_ci * audio standard of version 2 and other approved USB standards, even though
8848c2ecf20Sopenharmony_ci * they come up as vendor-specific device when first connected.
8858c2ecf20Sopenharmony_ci *
8868c2ecf20Sopenharmony_ci * However, they can be told to come up with a new set of descriptors
8878c2ecf20Sopenharmony_ci * upon their next enumeration, and the interfaces announced by the new
8888c2ecf20Sopenharmony_ci * descriptors will then be handled by the kernel's class drivers. As the
8898c2ecf20Sopenharmony_ci * product ID will also change, no further checks are required.
8908c2ecf20Sopenharmony_ci */
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	int ret;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
8978c2ecf20Sopenharmony_ci				  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
8988c2ecf20Sopenharmony_ci				  1, 0, NULL, 0, 1000);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (ret < 0)
9018c2ecf20Sopenharmony_ci		return ret;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	usb_reset_device(dev);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* return -EAGAIN, so the creation of an audio interface for this
9068c2ecf20Sopenharmony_ci	 * temporary device is aborted. The device will reconnect with a
9078c2ecf20Sopenharmony_ci	 * new product ID */
9088c2ecf20Sopenharmony_ci	return -EAGAIN;
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_cistatic void mbox2_setup_48_24_magic(struct usb_device *dev)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	u8 srate[3];
9148c2ecf20Sopenharmony_ci	u8 temp[12];
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* Choose 48000Hz permanently */
9178c2ecf20Sopenharmony_ci	srate[0] = 0x80;
9188c2ecf20Sopenharmony_ci	srate[1] = 0xbb;
9198c2ecf20Sopenharmony_ci	srate[2] = 0x00;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Send the magic! */
9228c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
9238c2ecf20Sopenharmony_ci		0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003);
9248c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
9258c2ecf20Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003);
9268c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
9278c2ecf20Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003);
9288c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
9298c2ecf20Sopenharmony_ci		0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003);
9308c2ecf20Sopenharmony_ci	return;
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci/* Digidesign Mbox 2 needs to load firmware onboard
9348c2ecf20Sopenharmony_ci * and driver must wait a few seconds for initialisation.
9358c2ecf20Sopenharmony_ci */
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci#define MBOX2_FIRMWARE_SIZE    646
9388c2ecf20Sopenharmony_ci#define MBOX2_BOOT_LOADING     0x01 /* Hard coded into the device */
9398c2ecf20Sopenharmony_ci#define MBOX2_BOOT_READY       0x02 /* Hard coded into the device */
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	struct usb_host_config *config = dev->actconfig;
9448c2ecf20Sopenharmony_ci	int err;
9458c2ecf20Sopenharmony_ci	u8 bootresponse[0x12];
9468c2ecf20Sopenharmony_ci	int fwsize;
9478c2ecf20Sopenharmony_ci	int count;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	if (fwsize != MBOX2_FIRMWARE_SIZE) {
9528c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Invalid firmware size=%d.\n", fwsize);
9538c2ecf20Sopenharmony_ci		return -ENODEV;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "Sending Digidesign Mbox 2 boot sequence...\n");
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	count = 0;
9598c2ecf20Sopenharmony_ci	bootresponse[0] = MBOX2_BOOT_LOADING;
9608c2ecf20Sopenharmony_ci	while ((bootresponse[0] == MBOX2_BOOT_LOADING) && (count < 10)) {
9618c2ecf20Sopenharmony_ci		msleep(500); /* 0.5 second delay */
9628c2ecf20Sopenharmony_ci		snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
9638c2ecf20Sopenharmony_ci			/* Control magic - load onboard firmware */
9648c2ecf20Sopenharmony_ci			0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012);
9658c2ecf20Sopenharmony_ci		if (bootresponse[0] == MBOX2_BOOT_READY)
9668c2ecf20Sopenharmony_ci			break;
9678c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "device not ready, resending boot sequence...\n");
9688c2ecf20Sopenharmony_ci		count++;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (bootresponse[0] != MBOX2_BOOT_READY) {
9728c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
9738c2ecf20Sopenharmony_ci		return -ENODEV;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "device initialised!\n");
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
9798c2ecf20Sopenharmony_ci		&dev->descriptor, sizeof(dev->descriptor));
9808c2ecf20Sopenharmony_ci	config = dev->actconfig;
9818c2ecf20Sopenharmony_ci	if (err < 0)
9828c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	err = usb_reset_configuration(dev);
9858c2ecf20Sopenharmony_ci	if (err < 0)
9868c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
9878c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "mbox2_boot: new boot length = %d\n",
9888c2ecf20Sopenharmony_ci		le16_to_cpu(get_cfg_desc(config)->wTotalLength));
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	mbox2_setup_48_24_magic(dev);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "Digidesign Mbox 2: 24bit 48kHz");
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	return 0; /* Successful boot */
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	int err;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n");
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* If the Axe-Fx III has not fully booted, it will timeout when trying
10048c2ecf20Sopenharmony_ci	 * to enable the audio streaming interface. A more generous timeout is
10058c2ecf20Sopenharmony_ci	 * used here to detect when the Axe-Fx III has finished booting as the
10068c2ecf20Sopenharmony_ci	 * set interface message will be acked once it has
10078c2ecf20Sopenharmony_ci	 */
10088c2ecf20Sopenharmony_ci	err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
10098c2ecf20Sopenharmony_ci				USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
10108c2ecf20Sopenharmony_ci				1, 1, NULL, 0, 120000);
10118c2ecf20Sopenharmony_ci	if (err < 0) {
10128c2ecf20Sopenharmony_ci		dev_err(&dev->dev,
10138c2ecf20Sopenharmony_ci			"failed waiting for Axe-Fx III to boot: %d\n", err);
10148c2ecf20Sopenharmony_ci		return err;
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "Axe-Fx III is now ready\n");
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	err = usb_set_interface(dev, 1, 0);
10208c2ecf20Sopenharmony_ci	if (err < 0)
10218c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev,
10228c2ecf20Sopenharmony_ci			"error stopping Axe-Fx III interface: %d\n", err);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	return 0;
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci#define MICROBOOK_BUF_SIZE 128
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
10318c2ecf20Sopenharmony_ci						int buf_size, int *length)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	int err, actual_length;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x01)))
10368c2ecf20Sopenharmony_ci		return -EINVAL;
10378c2ecf20Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
10388c2ecf20Sopenharmony_ci				&actual_length, 1000);
10398c2ecf20Sopenharmony_ci	if (err < 0)
10408c2ecf20Sopenharmony_ci		return err;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "MicroBookII snd: ", DUMP_PREFIX_NONE, 16, 1,
10438c2ecf20Sopenharmony_ci		       buf, actual_length, false);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	memset(buf, 0, buf_size);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	if (usb_pipe_type_check(dev, usb_rcvintpipe(dev, 0x82)))
10488c2ecf20Sopenharmony_ci		return -EINVAL;
10498c2ecf20Sopenharmony_ci	err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
10508c2ecf20Sopenharmony_ci				&actual_length, 1000);
10518c2ecf20Sopenharmony_ci	if (err < 0)
10528c2ecf20Sopenharmony_ci		return err;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "MicroBookII rcv: ", DUMP_PREFIX_NONE, 16, 1,
10558c2ecf20Sopenharmony_ci		       buf, actual_length, false);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	*length = actual_length;
10588c2ecf20Sopenharmony_ci	return 0;
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic int snd_usb_motu_microbookii_boot_quirk(struct usb_device *dev)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	int err, actual_length, poll_attempts = 0;
10648c2ecf20Sopenharmony_ci	static const u8 set_samplerate_seq[] = { 0x00, 0x00, 0x00, 0x00,
10658c2ecf20Sopenharmony_ci						 0x00, 0x00, 0x0b, 0x14,
10668c2ecf20Sopenharmony_ci						 0x00, 0x00, 0x00, 0x01 };
10678c2ecf20Sopenharmony_ci	static const u8 poll_ready_seq[] = { 0x00, 0x04, 0x00, 0x00,
10688c2ecf20Sopenharmony_ci					     0x00, 0x00, 0x0b, 0x18 };
10698c2ecf20Sopenharmony_ci	u8 *buf = kzalloc(MICROBOOK_BUF_SIZE, GFP_KERNEL);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	if (!buf)
10728c2ecf20Sopenharmony_ci		return -ENOMEM;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "Waiting for MOTU Microbook II to boot up...\n");
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	/* First we tell the device which sample rate to use. */
10778c2ecf20Sopenharmony_ci	memcpy(buf, set_samplerate_seq, sizeof(set_samplerate_seq));
10788c2ecf20Sopenharmony_ci	actual_length = sizeof(set_samplerate_seq);
10798c2ecf20Sopenharmony_ci	err = snd_usb_motu_microbookii_communicate(dev, buf, MICROBOOK_BUF_SIZE,
10808c2ecf20Sopenharmony_ci						   &actual_length);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	if (err < 0) {
10838c2ecf20Sopenharmony_ci		dev_err(&dev->dev,
10848c2ecf20Sopenharmony_ci			"failed setting the sample rate for Motu MicroBook II: %d\n",
10858c2ecf20Sopenharmony_ci			err);
10868c2ecf20Sopenharmony_ci		goto free_buf;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	/* Then we poll every 100 ms until the device informs of its readiness. */
10908c2ecf20Sopenharmony_ci	while (true) {
10918c2ecf20Sopenharmony_ci		if (++poll_attempts > 100) {
10928c2ecf20Sopenharmony_ci			dev_err(&dev->dev,
10938c2ecf20Sopenharmony_ci				"failed booting Motu MicroBook II: timeout\n");
10948c2ecf20Sopenharmony_ci			err = -ENODEV;
10958c2ecf20Sopenharmony_ci			goto free_buf;
10968c2ecf20Sopenharmony_ci		}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		memset(buf, 0, MICROBOOK_BUF_SIZE);
10998c2ecf20Sopenharmony_ci		memcpy(buf, poll_ready_seq, sizeof(poll_ready_seq));
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		actual_length = sizeof(poll_ready_seq);
11028c2ecf20Sopenharmony_ci		err = snd_usb_motu_microbookii_communicate(
11038c2ecf20Sopenharmony_ci			dev, buf, MICROBOOK_BUF_SIZE, &actual_length);
11048c2ecf20Sopenharmony_ci		if (err < 0) {
11058c2ecf20Sopenharmony_ci			dev_err(&dev->dev,
11068c2ecf20Sopenharmony_ci				"failed booting Motu MicroBook II: communication error %d\n",
11078c2ecf20Sopenharmony_ci				err);
11088c2ecf20Sopenharmony_ci			goto free_buf;
11098c2ecf20Sopenharmony_ci		}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci		/* the device signals its readiness through a message of the
11128c2ecf20Sopenharmony_ci		 * form
11138c2ecf20Sopenharmony_ci		 *           XX 06 00 00 00 00 0b 18  00 00 00 01
11148c2ecf20Sopenharmony_ci		 * If the device is not yet ready to accept audio data, the
11158c2ecf20Sopenharmony_ci		 * last byte of that sequence is 00.
11168c2ecf20Sopenharmony_ci		 */
11178c2ecf20Sopenharmony_ci		if (actual_length == 12 && buf[actual_length - 1] == 1)
11188c2ecf20Sopenharmony_ci			break;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci		msleep(100);
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "MOTU MicroBook II ready\n");
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cifree_buf:
11268c2ecf20Sopenharmony_ci	kfree(buf);
11278c2ecf20Sopenharmony_ci	return err;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	int ret;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
11358c2ecf20Sopenharmony_ci			      1, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
11368c2ecf20Sopenharmony_ci			      0x0, 0, NULL, 0, 1000);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	if (ret < 0)
11398c2ecf20Sopenharmony_ci		return ret;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	msleep(2000);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
11448c2ecf20Sopenharmony_ci			      1, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
11458c2ecf20Sopenharmony_ci			      0x20, 0, NULL, 0, 1000);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (ret < 0)
11488c2ecf20Sopenharmony_ci		return ret;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	return 0;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci/*
11548c2ecf20Sopenharmony_ci * Setup quirks
11558c2ecf20Sopenharmony_ci */
11568c2ecf20Sopenharmony_ci#define MAUDIO_SET		0x01 /* parse device_setup */
11578c2ecf20Sopenharmony_ci#define MAUDIO_SET_COMPATIBLE	0x80 /* use only "win-compatible" interfaces */
11588c2ecf20Sopenharmony_ci#define MAUDIO_SET_DTS		0x02 /* enable DTS Digital Output */
11598c2ecf20Sopenharmony_ci#define MAUDIO_SET_96K		0x04 /* 48-96kHz rate if set, 8-48kHz otherwise */
11608c2ecf20Sopenharmony_ci#define MAUDIO_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */
11618c2ecf20Sopenharmony_ci#define MAUDIO_SET_DI		0x10 /* enable Digital Input */
11628c2ecf20Sopenharmony_ci#define MAUDIO_SET_MASK		0x1f /* bit mask for setup value */
11638c2ecf20Sopenharmony_ci#define MAUDIO_SET_24B_48K_DI	 0x19 /* 24bits+48kHz+Digital Input */
11648c2ecf20Sopenharmony_ci#define MAUDIO_SET_24B_48K_NOTDI 0x09 /* 24bits+48kHz+No Digital Input */
11658c2ecf20Sopenharmony_ci#define MAUDIO_SET_16B_48K_DI	 0x11 /* 16bits+48kHz+Digital Input */
11668c2ecf20Sopenharmony_ci#define MAUDIO_SET_16B_48K_NOTDI 0x01 /* 16bits+48kHz+No Digital Input */
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int quattro_skip_setting_quirk(struct snd_usb_audio *chip,
11698c2ecf20Sopenharmony_ci				      int iface, int altno)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
11728c2ecf20Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
11738c2ecf20Sopenharmony_ci	 */
11748c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
11758c2ecf20Sopenharmony_ci	if (chip->setup & MAUDIO_SET) {
11768c2ecf20Sopenharmony_ci		if (chip->setup & MAUDIO_SET_COMPATIBLE) {
11778c2ecf20Sopenharmony_ci			if (iface != 1 && iface != 2)
11788c2ecf20Sopenharmony_ci				return 1; /* skip all interfaces but 1 and 2 */
11798c2ecf20Sopenharmony_ci		} else {
11808c2ecf20Sopenharmony_ci			unsigned int mask;
11818c2ecf20Sopenharmony_ci			if (iface == 1 || iface == 2)
11828c2ecf20Sopenharmony_ci				return 1; /* skip interfaces 1 and 2 */
11838c2ecf20Sopenharmony_ci			if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
11848c2ecf20Sopenharmony_ci				return 1; /* skip this altsetting */
11858c2ecf20Sopenharmony_ci			mask = chip->setup & MAUDIO_SET_MASK;
11868c2ecf20Sopenharmony_ci			if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
11878c2ecf20Sopenharmony_ci				return 1; /* skip this altsetting */
11888c2ecf20Sopenharmony_ci			if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
11898c2ecf20Sopenharmony_ci				return 1; /* skip this altsetting */
11908c2ecf20Sopenharmony_ci			if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 4)
11918c2ecf20Sopenharmony_ci				return 1; /* skip this altsetting */
11928c2ecf20Sopenharmony_ci		}
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci	usb_audio_dbg(chip,
11958c2ecf20Sopenharmony_ci		    "using altsetting %d for interface %d config %d\n",
11968c2ecf20Sopenharmony_ci		    altno, iface, chip->setup);
11978c2ecf20Sopenharmony_ci	return 0; /* keep this altsetting */
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_cistatic int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
12018c2ecf20Sopenharmony_ci					 int iface,
12028c2ecf20Sopenharmony_ci					 int altno)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
12058c2ecf20Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
12068c2ecf20Sopenharmony_ci	 */
12078c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	if (chip->setup & MAUDIO_SET) {
12108c2ecf20Sopenharmony_ci		unsigned int mask;
12118c2ecf20Sopenharmony_ci		if ((chip->setup & MAUDIO_SET_DTS) && altno != 6)
12128c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12138c2ecf20Sopenharmony_ci		if ((chip->setup & MAUDIO_SET_96K) && altno != 1)
12148c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12158c2ecf20Sopenharmony_ci		mask = chip->setup & MAUDIO_SET_MASK;
12168c2ecf20Sopenharmony_ci		if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)
12178c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12188c2ecf20Sopenharmony_ci		if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)
12198c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12208c2ecf20Sopenharmony_ci		if (mask == MAUDIO_SET_16B_48K_DI && altno != 4)
12218c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12228c2ecf20Sopenharmony_ci		if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 5)
12238c2ecf20Sopenharmony_ci			return 1; /* skip this altsetting */
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	return 0; /* keep this altsetting */
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cistatic int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
12308c2ecf20Sopenharmony_ci					   int iface, int altno)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	/* Reset ALL ifaces to 0 altsetting.
12338c2ecf20Sopenharmony_ci	 * Call it for every possible altsetting of every interface.
12348c2ecf20Sopenharmony_ci	 */
12358c2ecf20Sopenharmony_ci	usb_set_interface(chip->dev, iface, 0);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	/* possible configuration where both inputs and only one output is
12388c2ecf20Sopenharmony_ci	 *used is not supported by the current setup
12398c2ecf20Sopenharmony_ci	 */
12408c2ecf20Sopenharmony_ci	if (chip->setup & (MAUDIO_SET | MAUDIO_SET_24B)) {
12418c2ecf20Sopenharmony_ci		if (chip->setup & MAUDIO_SET_96K) {
12428c2ecf20Sopenharmony_ci			if (altno != 3 && altno != 6)
12438c2ecf20Sopenharmony_ci				return 1;
12448c2ecf20Sopenharmony_ci		} else if (chip->setup & MAUDIO_SET_DI) {
12458c2ecf20Sopenharmony_ci			if (iface == 4)
12468c2ecf20Sopenharmony_ci				return 1; /* no analog input */
12478c2ecf20Sopenharmony_ci			if (altno != 2 && altno != 5)
12488c2ecf20Sopenharmony_ci				return 1; /* enable only altsets 2 and 5 */
12498c2ecf20Sopenharmony_ci		} else {
12508c2ecf20Sopenharmony_ci			if (iface == 5)
12518c2ecf20Sopenharmony_ci				return 1; /* disable digialt input */
12528c2ecf20Sopenharmony_ci			if (altno != 2 && altno != 5)
12538c2ecf20Sopenharmony_ci				return 1; /* enalbe only altsets 2 and 5 */
12548c2ecf20Sopenharmony_ci		}
12558c2ecf20Sopenharmony_ci	} else {
12568c2ecf20Sopenharmony_ci		/* keep only 16-Bit mode */
12578c2ecf20Sopenharmony_ci		if (altno != 1)
12588c2ecf20Sopenharmony_ci			return 1;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	usb_audio_dbg(chip,
12628c2ecf20Sopenharmony_ci		    "using altsetting %d for interface %d config %d\n",
12638c2ecf20Sopenharmony_ci		    altno, iface, chip->setup);
12648c2ecf20Sopenharmony_ci	return 0; /* keep this altsetting */
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic int s1810c_skip_setting_quirk(struct snd_usb_audio *chip,
12688c2ecf20Sopenharmony_ci					   int iface, int altno)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	/*
12718c2ecf20Sopenharmony_ci	 * Altno settings:
12728c2ecf20Sopenharmony_ci	 *
12738c2ecf20Sopenharmony_ci	 * Playback (Interface 1):
12748c2ecf20Sopenharmony_ci	 * 1: 6 Analog + 2 S/PDIF
12758c2ecf20Sopenharmony_ci	 * 2: 6 Analog + 2 S/PDIF
12768c2ecf20Sopenharmony_ci	 * 3: 6 Analog
12778c2ecf20Sopenharmony_ci	 *
12788c2ecf20Sopenharmony_ci	 * Capture (Interface 2):
12798c2ecf20Sopenharmony_ci	 * 1: 8 Analog + 2 S/PDIF + 8 ADAT
12808c2ecf20Sopenharmony_ci	 * 2: 8 Analog + 2 S/PDIF + 4 ADAT
12818c2ecf20Sopenharmony_ci	 * 3: 8 Analog
12828c2ecf20Sopenharmony_ci	 */
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	/*
12858c2ecf20Sopenharmony_ci	 * I'll leave 2 as the default one and
12868c2ecf20Sopenharmony_ci	 * use device_setup to switch to the
12878c2ecf20Sopenharmony_ci	 * other two.
12888c2ecf20Sopenharmony_ci	 */
12898c2ecf20Sopenharmony_ci	if ((chip->setup == 0 || chip->setup > 2) && altno != 2)
12908c2ecf20Sopenharmony_ci		return 1;
12918c2ecf20Sopenharmony_ci	else if (chip->setup == 1 && altno != 1)
12928c2ecf20Sopenharmony_ci		return 1;
12938c2ecf20Sopenharmony_ci	else if (chip->setup == 2 && altno != 3)
12948c2ecf20Sopenharmony_ci		return 1;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	return 0;
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ciint snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
13008c2ecf20Sopenharmony_ci				  int iface,
13018c2ecf20Sopenharmony_ci				  int altno)
13028c2ecf20Sopenharmony_ci{
13038c2ecf20Sopenharmony_ci	/* audiophile usb: skip altsets incompatible with device_setup */
13048c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2003))
13058c2ecf20Sopenharmony_ci		return audiophile_skip_setting_quirk(chip, iface, altno);
13068c2ecf20Sopenharmony_ci	/* quattro usb: skip altsets incompatible with device_setup */
13078c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2001))
13088c2ecf20Sopenharmony_ci		return quattro_skip_setting_quirk(chip, iface, altno);
13098c2ecf20Sopenharmony_ci	/* fasttrackpro usb: skip altsets incompatible with device_setup */
13108c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x0763, 0x2012))
13118c2ecf20Sopenharmony_ci		return fasttrackpro_skip_setting_quirk(chip, iface, altno);
13128c2ecf20Sopenharmony_ci	/* presonus studio 1810c: skip altsets incompatible with device_setup */
13138c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x194f, 0x010c))
13148c2ecf20Sopenharmony_ci		return s1810c_skip_setting_quirk(chip, iface, altno);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	return 0;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ciint snd_usb_apply_boot_quirk(struct usb_device *dev,
13218c2ecf20Sopenharmony_ci			     struct usb_interface *intf,
13228c2ecf20Sopenharmony_ci			     const struct snd_usb_audio_quirk *quirk,
13238c2ecf20Sopenharmony_ci			     unsigned int id)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	switch (id) {
13268c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3000):
13278c2ecf20Sopenharmony_ci		/* SB Extigy needs special boot-up sequence */
13288c2ecf20Sopenharmony_ci		/* if more models come, this will go to the quirk list. */
13298c2ecf20Sopenharmony_ci		return snd_usb_extigy_boot_quirk(dev, intf);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3020):
13328c2ecf20Sopenharmony_ci		/* SB Audigy 2 NX needs its own boot-up magic, too */
13338c2ecf20Sopenharmony_ci		return snd_usb_audigy2nx_boot_quirk(dev);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	case USB_ID(0x10f5, 0x0200):
13368c2ecf20Sopenharmony_ci		/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
13378c2ecf20Sopenharmony_ci		return snd_usb_cm106_boot_quirk(dev);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	case USB_ID(0x0d8c, 0x0102):
13408c2ecf20Sopenharmony_ci		/* C-Media CM6206 / CM106-Like Sound Device */
13418c2ecf20Sopenharmony_ci	case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */
13428c2ecf20Sopenharmony_ci		return snd_usb_cm6206_boot_quirk(dev);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	case USB_ID(0x0dba, 0x3000):
13458c2ecf20Sopenharmony_ci		/* Digidesign Mbox 2 */
13468c2ecf20Sopenharmony_ci		return snd_usb_mbox2_boot_quirk(dev);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */
13498c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */
13508c2ecf20Sopenharmony_ci		return snd_usb_novation_boot_quirk(dev);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	case USB_ID(0x133e, 0x0815):
13538c2ecf20Sopenharmony_ci		/* Access Music VirusTI Desktop */
13548c2ecf20Sopenharmony_ci		return snd_usb_accessmusic_boot_quirk(dev);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */
13578c2ecf20Sopenharmony_ci	case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
13588c2ecf20Sopenharmony_ci	case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
13598c2ecf20Sopenharmony_ci		return snd_usb_nativeinstruments_boot_quirk(dev);
13608c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
13618c2ecf20Sopenharmony_ci		return snd_usb_fasttrackpro_boot_quirk(dev);
13628c2ecf20Sopenharmony_ci	case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */
13638c2ecf20Sopenharmony_ci		return snd_usb_gamecon780_boot_quirk(dev);
13648c2ecf20Sopenharmony_ci	case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */
13658c2ecf20Sopenharmony_ci		return snd_usb_axefx3_boot_quirk(dev);
13668c2ecf20Sopenharmony_ci	case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */
13678c2ecf20Sopenharmony_ci		/*
13688c2ecf20Sopenharmony_ci		 * For some reason interface 3 with vendor-spec class is
13698c2ecf20Sopenharmony_ci		 * detected on MicroBook IIc.
13708c2ecf20Sopenharmony_ci		 */
13718c2ecf20Sopenharmony_ci		if (get_iface_desc(intf->altsetting)->bInterfaceClass ==
13728c2ecf20Sopenharmony_ci		    USB_CLASS_VENDOR_SPEC &&
13738c2ecf20Sopenharmony_ci		    get_iface_desc(intf->altsetting)->bInterfaceNumber < 3)
13748c2ecf20Sopenharmony_ci			return snd_usb_motu_microbookii_boot_quirk(dev);
13758c2ecf20Sopenharmony_ci		break;
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	return 0;
13798c2ecf20Sopenharmony_ci}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ciint snd_usb_apply_boot_quirk_once(struct usb_device *dev,
13828c2ecf20Sopenharmony_ci				  struct usb_interface *intf,
13838c2ecf20Sopenharmony_ci				  const struct snd_usb_audio_quirk *quirk,
13848c2ecf20Sopenharmony_ci				  unsigned int id)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	switch (id) {
13878c2ecf20Sopenharmony_ci	case USB_ID(0x07fd, 0x0008): /* MOTU M Series */
13888c2ecf20Sopenharmony_ci		return snd_usb_motu_m_series_boot_quirk(dev);
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	return 0;
13928c2ecf20Sopenharmony_ci}
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci/*
13958c2ecf20Sopenharmony_ci * check if the device uses big-endian samples
13968c2ecf20Sopenharmony_ci */
13978c2ecf20Sopenharmony_ciint snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	/* it depends on altsetting whether the device is big-endian or not */
14008c2ecf20Sopenharmony_ci	switch (chip->usb_id) {
14018c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
14028c2ecf20Sopenharmony_ci		if (fp->altsetting == 2 || fp->altsetting == 3 ||
14038c2ecf20Sopenharmony_ci			fp->altsetting == 5 || fp->altsetting == 6)
14048c2ecf20Sopenharmony_ci			return 1;
14058c2ecf20Sopenharmony_ci		break;
14068c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
14078c2ecf20Sopenharmony_ci		if (chip->setup == 0x00 ||
14088c2ecf20Sopenharmony_ci			fp->altsetting == 1 || fp->altsetting == 2 ||
14098c2ecf20Sopenharmony_ci			fp->altsetting == 3)
14108c2ecf20Sopenharmony_ci			return 1;
14118c2ecf20Sopenharmony_ci		break;
14128c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro */
14138c2ecf20Sopenharmony_ci		if (fp->altsetting == 2 || fp->altsetting == 3 ||
14148c2ecf20Sopenharmony_ci			fp->altsetting == 5 || fp->altsetting == 6)
14158c2ecf20Sopenharmony_ci			return 1;
14168c2ecf20Sopenharmony_ci		break;
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci	return 0;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci/*
14228c2ecf20Sopenharmony_ci * For E-Mu 0404USB/0202USB/TrackerPre/0204 sample rate should be set for device,
14238c2ecf20Sopenharmony_ci * not for interface.
14248c2ecf20Sopenharmony_ci */
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_cienum {
14278c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_44100HZ = 0,
14288c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_48000HZ,
14298c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_88200HZ,
14308c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_96000HZ,
14318c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_176400HZ,
14328c2ecf20Sopenharmony_ci	EMU_QUIRK_SR_192000HZ
14338c2ecf20Sopenharmony_ci};
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cistatic void set_format_emu_quirk(struct snd_usb_substream *subs,
14368c2ecf20Sopenharmony_ci				 struct audioformat *fmt)
14378c2ecf20Sopenharmony_ci{
14388c2ecf20Sopenharmony_ci	unsigned char emu_samplerate_id = 0;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	/* When capture is active
14418c2ecf20Sopenharmony_ci	 * sample rate shouldn't be changed
14428c2ecf20Sopenharmony_ci	 * by playback substream
14438c2ecf20Sopenharmony_ci	 */
14448c2ecf20Sopenharmony_ci	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
14458c2ecf20Sopenharmony_ci		if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1)
14468c2ecf20Sopenharmony_ci			return;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	switch (fmt->rate_min) {
14508c2ecf20Sopenharmony_ci	case 48000:
14518c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_48000HZ;
14528c2ecf20Sopenharmony_ci		break;
14538c2ecf20Sopenharmony_ci	case 88200:
14548c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_88200HZ;
14558c2ecf20Sopenharmony_ci		break;
14568c2ecf20Sopenharmony_ci	case 96000:
14578c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_96000HZ;
14588c2ecf20Sopenharmony_ci		break;
14598c2ecf20Sopenharmony_ci	case 176400:
14608c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_176400HZ;
14618c2ecf20Sopenharmony_ci		break;
14628c2ecf20Sopenharmony_ci	case 192000:
14638c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_192000HZ;
14648c2ecf20Sopenharmony_ci		break;
14658c2ecf20Sopenharmony_ci	default:
14668c2ecf20Sopenharmony_ci		emu_samplerate_id = EMU_QUIRK_SR_44100HZ;
14678c2ecf20Sopenharmony_ci		break;
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
14708c2ecf20Sopenharmony_ci	subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
14718c2ecf20Sopenharmony_ci}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci/*
14758c2ecf20Sopenharmony_ci * Pioneer DJ DJM-900NXS2
14768c2ecf20Sopenharmony_ci * Device needs to know the sample rate each time substream is started
14778c2ecf20Sopenharmony_ci */
14788c2ecf20Sopenharmony_cistatic int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs)
14798c2ecf20Sopenharmony_ci{
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	/* Convert sample rate value to little endian */
14828c2ecf20Sopenharmony_ci	u8 sr[3];
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	sr[0] = subs->cur_rate & 0xff;
14858c2ecf20Sopenharmony_ci	sr[1] = (subs->cur_rate >> 8) & 0xff;
14868c2ecf20Sopenharmony_ci	sr[2] = (subs->cur_rate >> 16) & 0xff;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	/* Configure device */
14898c2ecf20Sopenharmony_ci	usb_set_interface(subs->dev, 0, 1);
14908c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(subs->stream->chip->dev,
14918c2ecf20Sopenharmony_ci		usb_rcvctrlpipe(subs->stream->chip->dev, 0),
14928c2ecf20Sopenharmony_ci		0x01, 0x22, 0x0100, 0x0082, &sr, 0x0003);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	return 0;
14958c2ecf20Sopenharmony_ci}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_civoid snd_usb_set_format_quirk(struct snd_usb_substream *subs,
14988c2ecf20Sopenharmony_ci			      struct audioformat *fmt)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	switch (subs->stream->chip->usb_id) {
15018c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
15028c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
15038c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
15048c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
15058c2ecf20Sopenharmony_ci		set_format_emu_quirk(subs, fmt);
15068c2ecf20Sopenharmony_ci		break;
15078c2ecf20Sopenharmony_ci	case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
15088c2ecf20Sopenharmony_ci	case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
15098c2ecf20Sopenharmony_ci		pioneer_djm_set_format_quirk(subs);
15108c2ecf20Sopenharmony_ci		break;
15118c2ecf20Sopenharmony_ci	case USB_ID(0x534d, 0x0021): /* MacroSilicon MS2100/MS2106 */
15128c2ecf20Sopenharmony_ci	case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
15138c2ecf20Sopenharmony_ci		subs->stream_offset_adj = 2;
15148c2ecf20Sopenharmony_ci		break;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_cibool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	/* devices which do not support reading the sample rate. */
15218c2ecf20Sopenharmony_ci	switch (chip->usb_id) {
15228c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x4080): /* Creative Live Cam VF0610 */
15238c2ecf20Sopenharmony_ci	case USB_ID(0x04d8, 0xfeea): /* Benchmark DAC1 Pre */
15248c2ecf20Sopenharmony_ci	case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
15258c2ecf20Sopenharmony_ci	case USB_ID(0x05a3, 0x9420): /* ELP HD USB Camera */
15268c2ecf20Sopenharmony_ci	case USB_ID(0x05a7, 0x1020): /* Bose Companion 5 */
15278c2ecf20Sopenharmony_ci	case USB_ID(0x074d, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
15288c2ecf20Sopenharmony_ci	case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
15298c2ecf20Sopenharmony_ci	case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
15308c2ecf20Sopenharmony_ci	case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
15318c2ecf20Sopenharmony_ci	case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
15328c2ecf20Sopenharmony_ci	case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
15338c2ecf20Sopenharmony_ci	case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */
15348c2ecf20Sopenharmony_ci		return true;
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	/* devices of these vendors don't support reading rate, either */
15388c2ecf20Sopenharmony_ci	switch (USB_ID_VENDOR(chip->usb_id)) {
15398c2ecf20Sopenharmony_ci	case 0x045e: /* MS Lifecam */
15408c2ecf20Sopenharmony_ci	case 0x047f: /* Plantronics */
15418c2ecf20Sopenharmony_ci	case 0x1de7: /* Phoenix Audio */
15428c2ecf20Sopenharmony_ci		return true;
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	return false;
15468c2ecf20Sopenharmony_ci}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci/* ITF-USB DSD based DACs need a vendor cmd to switch
15498c2ecf20Sopenharmony_ci * between PCM and native DSD mode
15508c2ecf20Sopenharmony_ci */
15518c2ecf20Sopenharmony_cistatic bool is_itf_usb_dsd_dac(unsigned int id)
15528c2ecf20Sopenharmony_ci{
15538c2ecf20Sopenharmony_ci	switch (id) {
15548c2ecf20Sopenharmony_ci	case USB_ID(0x154e, 0x1002): /* Denon DCD-1500RE */
15558c2ecf20Sopenharmony_ci	case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
15568c2ecf20Sopenharmony_ci	case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
15578c2ecf20Sopenharmony_ci	case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
15588c2ecf20Sopenharmony_ci	case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */
15598c2ecf20Sopenharmony_ci	case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
15608c2ecf20Sopenharmony_ci	case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
15618c2ecf20Sopenharmony_ci	case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
15628c2ecf20Sopenharmony_ci		return true;
15638c2ecf20Sopenharmony_ci	}
15648c2ecf20Sopenharmony_ci	return false;
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ciint snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
15688c2ecf20Sopenharmony_ci			      struct audioformat *fmt)
15698c2ecf20Sopenharmony_ci{
15708c2ecf20Sopenharmony_ci	struct usb_device *dev = subs->dev;
15718c2ecf20Sopenharmony_ci	int err;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (is_itf_usb_dsd_dac(subs->stream->chip->usb_id)) {
15748c2ecf20Sopenharmony_ci		/* First switch to alt set 0, otherwise the mode switch cmd
15758c2ecf20Sopenharmony_ci		 * will not be accepted by the DAC
15768c2ecf20Sopenharmony_ci		 */
15778c2ecf20Sopenharmony_ci		err = usb_set_interface(dev, fmt->iface, 0);
15788c2ecf20Sopenharmony_ci		if (err < 0)
15798c2ecf20Sopenharmony_ci			return err;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		msleep(20); /* Delay needed after setting the interface */
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci		/* Vendor mode switch cmd is required. */
15848c2ecf20Sopenharmony_ci		if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) {
15858c2ecf20Sopenharmony_ci			/* DSD mode (DSD_U32) requested */
15868c2ecf20Sopenharmony_ci			err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
15878c2ecf20Sopenharmony_ci					      USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
15888c2ecf20Sopenharmony_ci					      1, 1, NULL, 0);
15898c2ecf20Sopenharmony_ci			if (err < 0)
15908c2ecf20Sopenharmony_ci				return err;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci		} else {
15938c2ecf20Sopenharmony_ci			/* PCM or DOP mode (S32) requested */
15948c2ecf20Sopenharmony_ci			/* PCM mode (S16) requested */
15958c2ecf20Sopenharmony_ci			err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
15968c2ecf20Sopenharmony_ci					      USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
15978c2ecf20Sopenharmony_ci					      0, 1, NULL, 0);
15988c2ecf20Sopenharmony_ci			if (err < 0)
15998c2ecf20Sopenharmony_ci				return err;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		}
16028c2ecf20Sopenharmony_ci		msleep(20);
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci	return 0;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_civoid snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	/*
16108c2ecf20Sopenharmony_ci	 * "Playback Design" products send bogus feedback data at the start
16118c2ecf20Sopenharmony_ci	 * of the stream. Ignore them.
16128c2ecf20Sopenharmony_ci	 */
16138c2ecf20Sopenharmony_ci	if (USB_ID_VENDOR(ep->chip->usb_id) == 0x23ba &&
16148c2ecf20Sopenharmony_ci	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
16158c2ecf20Sopenharmony_ci		ep->skip_packets = 4;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	/*
16188c2ecf20Sopenharmony_ci	 * M-Audio Fast Track C400/C600 - when packets are not skipped, real
16198c2ecf20Sopenharmony_ci	 * world latency varies by approx. +/- 50 frames (at 96kHz) each time
16208c2ecf20Sopenharmony_ci	 * the stream is (re)started. When skipping packets 16 at endpoint
16218c2ecf20Sopenharmony_ci	 * start up, the real world latency is stable within +/- 1 frame (also
16228c2ecf20Sopenharmony_ci	 * across power cycles).
16238c2ecf20Sopenharmony_ci	 */
16248c2ecf20Sopenharmony_ci	if ((ep->chip->usb_id == USB_ID(0x0763, 0x2030) ||
16258c2ecf20Sopenharmony_ci	     ep->chip->usb_id == USB_ID(0x0763, 0x2031)) &&
16268c2ecf20Sopenharmony_ci	    ep->type == SND_USB_ENDPOINT_TYPE_DATA)
16278c2ecf20Sopenharmony_ci		ep->skip_packets = 16;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	/* Work around devices that report unreasonable feedback data */
16308c2ecf20Sopenharmony_ci	if ((ep->chip->usb_id == USB_ID(0x0644, 0x8038) ||  /* TEAC UD-H01 */
16318c2ecf20Sopenharmony_ci	     ep->chip->usb_id == USB_ID(0x1852, 0x5034)) && /* T+A Dac8 */
16328c2ecf20Sopenharmony_ci	    ep->syncmaxsize == 4)
16338c2ecf20Sopenharmony_ci		ep->tenor_fb_quirk = 1;
16348c2ecf20Sopenharmony_ci}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_civoid snd_usb_set_interface_quirk(struct usb_device *dev)
16378c2ecf20Sopenharmony_ci{
16388c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = dev_get_drvdata(&dev->dev);
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	if (!chip)
16418c2ecf20Sopenharmony_ci		return;
16428c2ecf20Sopenharmony_ci	/*
16438c2ecf20Sopenharmony_ci	 * "Playback Design" products need a 50ms delay after setting the
16448c2ecf20Sopenharmony_ci	 * USB interface.
16458c2ecf20Sopenharmony_ci	 */
16468c2ecf20Sopenharmony_ci	switch (USB_ID_VENDOR(chip->usb_id)) {
16478c2ecf20Sopenharmony_ci	case 0x23ba: /* Playback Design */
16488c2ecf20Sopenharmony_ci	case 0x0644: /* TEAC Corp. */
16498c2ecf20Sopenharmony_ci		msleep(50);
16508c2ecf20Sopenharmony_ci		break;
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci/* quirk applied after snd_usb_ctl_msg(); not applied during boot quirks */
16558c2ecf20Sopenharmony_civoid snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
16568c2ecf20Sopenharmony_ci			   __u8 request, __u8 requesttype, __u16 value,
16578c2ecf20Sopenharmony_ci			   __u16 index, void *data, __u16 size)
16588c2ecf20Sopenharmony_ci{
16598c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = dev_get_drvdata(&dev->dev);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (!chip)
16628c2ecf20Sopenharmony_ci		return;
16638c2ecf20Sopenharmony_ci	/*
16648c2ecf20Sopenharmony_ci	 * "Playback Design" products need a 20ms delay after each
16658c2ecf20Sopenharmony_ci	 * class compliant request
16668c2ecf20Sopenharmony_ci	 */
16678c2ecf20Sopenharmony_ci	if (USB_ID_VENDOR(chip->usb_id) == 0x23ba &&
16688c2ecf20Sopenharmony_ci	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
16698c2ecf20Sopenharmony_ci		msleep(20);
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	/*
16728c2ecf20Sopenharmony_ci	 * "TEAC Corp." products need a 20ms delay after each
16738c2ecf20Sopenharmony_ci	 * class compliant request
16748c2ecf20Sopenharmony_ci	 */
16758c2ecf20Sopenharmony_ci	if (USB_ID_VENDOR(chip->usb_id) == 0x0644 &&
16768c2ecf20Sopenharmony_ci	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
16778c2ecf20Sopenharmony_ci		msleep(20);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	/* ITF-USB DSD based DACs functionality need a delay
16808c2ecf20Sopenharmony_ci	 * after each class compliant request
16818c2ecf20Sopenharmony_ci	 */
16828c2ecf20Sopenharmony_ci	if (is_itf_usb_dsd_dac(chip->usb_id)
16838c2ecf20Sopenharmony_ci	    && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
16848c2ecf20Sopenharmony_ci		msleep(20);
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	/*
16878c2ecf20Sopenharmony_ci	 * Plantronics headsets (C320, C320-M, etc) need a delay to avoid
16888c2ecf20Sopenharmony_ci	 * random microhpone failures.
16898c2ecf20Sopenharmony_ci	 */
16908c2ecf20Sopenharmony_ci	if (USB_ID_VENDOR(chip->usb_id) == 0x047f &&
16918c2ecf20Sopenharmony_ci	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
16928c2ecf20Sopenharmony_ci		msleep(20);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	/* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950),
16958c2ecf20Sopenharmony_ci	 * Jabra 550a, Kingston HyperX needs a tiny delay here,
16968c2ecf20Sopenharmony_ci	 * otherwise requests like get/set frequency return
16978c2ecf20Sopenharmony_ci	 * as failed despite actually succeeding.
16988c2ecf20Sopenharmony_ci	 */
16998c2ecf20Sopenharmony_ci	if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
17008c2ecf20Sopenharmony_ci	     USB_ID_VENDOR(chip->usb_id) == 0x046d  || /* Logitech */
17018c2ecf20Sopenharmony_ci	     chip->usb_id == USB_ID(0x0b0e, 0x0349) ||
17028c2ecf20Sopenharmony_ci	     chip->usb_id == USB_ID(0x0951, 0x16ad)) &&
17038c2ecf20Sopenharmony_ci	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
17048c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	/*
17078c2ecf20Sopenharmony_ci	 * Samsung USBC Headset (AKG) need a tiny delay after each
17088c2ecf20Sopenharmony_ci	 * class compliant request. (Model number: AAM625R or AAM627R)
17098c2ecf20Sopenharmony_ci	 */
17108c2ecf20Sopenharmony_ci	if (chip->usb_id == USB_ID(0x04e8, 0xa051) &&
17118c2ecf20Sopenharmony_ci	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
17128c2ecf20Sopenharmony_ci		usleep_range(5000, 6000);
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci/*
17168c2ecf20Sopenharmony_ci * snd_usb_interface_dsd_format_quirks() is called from format.c to
17178c2ecf20Sopenharmony_ci * augment the PCM format bit-field for DSD types. The UAC standards
17188c2ecf20Sopenharmony_ci * don't have a designated bit field to denote DSD-capable interfaces,
17198c2ecf20Sopenharmony_ci * hence all hardware that is known to support this format has to be
17208c2ecf20Sopenharmony_ci * listed here.
17218c2ecf20Sopenharmony_ci */
17228c2ecf20Sopenharmony_ciu64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
17238c2ecf20Sopenharmony_ci					struct audioformat *fp,
17248c2ecf20Sopenharmony_ci					unsigned int sample_bytes)
17258c2ecf20Sopenharmony_ci{
17268c2ecf20Sopenharmony_ci	struct usb_interface *iface;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	/* Playback Designs */
17298c2ecf20Sopenharmony_ci	if (USB_ID_VENDOR(chip->usb_id) == 0x23ba &&
17308c2ecf20Sopenharmony_ci	    USB_ID_PRODUCT(chip->usb_id) < 0x0110) {
17318c2ecf20Sopenharmony_ci		switch (fp->altsetting) {
17328c2ecf20Sopenharmony_ci		case 1:
17338c2ecf20Sopenharmony_ci			fp->dsd_dop = true;
17348c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
17358c2ecf20Sopenharmony_ci		case 2:
17368c2ecf20Sopenharmony_ci			fp->dsd_bitrev = true;
17378c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U8;
17388c2ecf20Sopenharmony_ci		case 3:
17398c2ecf20Sopenharmony_ci			fp->dsd_bitrev = true;
17408c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U16_LE;
17418c2ecf20Sopenharmony_ci		}
17428c2ecf20Sopenharmony_ci	}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	/* XMOS based USB DACs */
17458c2ecf20Sopenharmony_ci	switch (chip->usb_id) {
17468c2ecf20Sopenharmony_ci	case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */
17478c2ecf20Sopenharmony_ci	case USB_ID(0x21ed, 0xd75a): /* Accuphase DAC-60 option card */
17488c2ecf20Sopenharmony_ci	case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */
17498c2ecf20Sopenharmony_ci	case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */
17508c2ecf20Sopenharmony_ci		if (fp->altsetting == 2)
17518c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
17528c2ecf20Sopenharmony_ci		break;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */
17558c2ecf20Sopenharmony_ci	case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */
17568c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x06b2): /* NuPrime DAC-10 */
17578c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */
17588c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */
17598c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */
17608c2ecf20Sopenharmony_ci	case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */
17618c2ecf20Sopenharmony_ci	case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */
17628c2ecf20Sopenharmony_ci	case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */
17638c2ecf20Sopenharmony_ci	case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */
17648c2ecf20Sopenharmony_ci	case USB_ID(0x2622, 0x0041): /* Audiolab M-DAC+ */
17658c2ecf20Sopenharmony_ci	case USB_ID(0x27f7, 0x3002): /* W4S DAC-2v2SE */
17668c2ecf20Sopenharmony_ci	case USB_ID(0x29a2, 0x0086): /* Mutec MC3+ USB */
17678c2ecf20Sopenharmony_ci	case USB_ID(0x6b42, 0x0042): /* MSB Technology */
17688c2ecf20Sopenharmony_ci		if (fp->altsetting == 3)
17698c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
17708c2ecf20Sopenharmony_ci		break;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	/* Amanero Combo384 USB based DACs with native DSD support */
17738c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x071a):  /* Amanero - Combo384 */
17748c2ecf20Sopenharmony_ci	case USB_ID(0x2ab6, 0x0004):  /* T+A DAC8DSD-V2.0, MP1000E-V2.0, MP2000R-V2.0, MP2500R-V2.0, MP3100HV-V2.0 */
17758c2ecf20Sopenharmony_ci	case USB_ID(0x2ab6, 0x0005):  /* T+A USB HD Audio 1 */
17768c2ecf20Sopenharmony_ci	case USB_ID(0x2ab6, 0x0006):  /* T+A USB HD Audio 2 */
17778c2ecf20Sopenharmony_ci		if (fp->altsetting == 2) {
17788c2ecf20Sopenharmony_ci			switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) {
17798c2ecf20Sopenharmony_ci			case 0x199:
17808c2ecf20Sopenharmony_ci				return SNDRV_PCM_FMTBIT_DSD_U32_LE;
17818c2ecf20Sopenharmony_ci			case 0x19b:
17828c2ecf20Sopenharmony_ci			case 0x203:
17838c2ecf20Sopenharmony_ci				return SNDRV_PCM_FMTBIT_DSD_U32_BE;
17848c2ecf20Sopenharmony_ci			default:
17858c2ecf20Sopenharmony_ci				break;
17868c2ecf20Sopenharmony_ci			}
17878c2ecf20Sopenharmony_ci		}
17888c2ecf20Sopenharmony_ci		break;
17898c2ecf20Sopenharmony_ci	case USB_ID(0x16d0, 0x0a23):
17908c2ecf20Sopenharmony_ci		if (fp->altsetting == 2)
17918c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
17928c2ecf20Sopenharmony_ci		break;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	default:
17958c2ecf20Sopenharmony_ci		break;
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	/* ITF-USB DSD based DACs */
17998c2ecf20Sopenharmony_ci	if (is_itf_usb_dsd_dac(chip->usb_id)) {
18008c2ecf20Sopenharmony_ci		iface = usb_ifnum_to_if(chip->dev, fp->iface);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		/* Altsetting 2 support native DSD if the num of altsets is
18038c2ecf20Sopenharmony_ci		 * three (0-2),
18048c2ecf20Sopenharmony_ci		 * Altsetting 3 support native DSD if the num of altsets is
18058c2ecf20Sopenharmony_ci		 * four (0-3).
18068c2ecf20Sopenharmony_ci		 */
18078c2ecf20Sopenharmony_ci		if (fp->altsetting == iface->num_altsetting - 1)
18088c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	/* Mostly generic method to detect many DSD-capable implementations -
18128c2ecf20Sopenharmony_ci	 * from XMOS/Thesycon
18138c2ecf20Sopenharmony_ci	 */
18148c2ecf20Sopenharmony_ci	switch (USB_ID_VENDOR(chip->usb_id)) {
18158c2ecf20Sopenharmony_ci	case 0x152a:  /* Thesycon devices */
18168c2ecf20Sopenharmony_ci	case 0x20b1:  /* XMOS based devices */
18178c2ecf20Sopenharmony_ci	case 0x22d9:  /* Oppo */
18188c2ecf20Sopenharmony_ci	case 0x23ba:  /* Playback Designs */
18198c2ecf20Sopenharmony_ci	case 0x25ce:  /* Mytek devices */
18208c2ecf20Sopenharmony_ci	case 0x278b:  /* Rotel? */
18218c2ecf20Sopenharmony_ci	case 0x292b:  /* Gustard/Ess based devices */
18228c2ecf20Sopenharmony_ci	case 0x2972:  /* FiiO devices */
18238c2ecf20Sopenharmony_ci	case 0x2ab6:  /* T+A devices */
18248c2ecf20Sopenharmony_ci	case 0x3353:  /* Khadas devices */
18258c2ecf20Sopenharmony_ci	case 0x3842:  /* EVGA */
18268c2ecf20Sopenharmony_ci	case 0xc502:  /* HiBy devices */
18278c2ecf20Sopenharmony_ci		if (fp->dsd_raw)
18288c2ecf20Sopenharmony_ci			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
18298c2ecf20Sopenharmony_ci		break;
18308c2ecf20Sopenharmony_ci	default:
18318c2ecf20Sopenharmony_ci		break;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	return 0;
18368c2ecf20Sopenharmony_ci}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_civoid snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
18398c2ecf20Sopenharmony_ci					  struct audioformat *fp,
18408c2ecf20Sopenharmony_ci					  int stream)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	switch (chip->usb_id) {
18438c2ecf20Sopenharmony_ci	case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
18448c2ecf20Sopenharmony_ci		/* Optoplay sets the sample rate attribute although
18458c2ecf20Sopenharmony_ci		 * it seems not supporting it in fact.
18468c2ecf20Sopenharmony_ci		 */
18478c2ecf20Sopenharmony_ci		fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
18488c2ecf20Sopenharmony_ci		break;
18498c2ecf20Sopenharmony_ci	case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
18508c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
18518c2ecf20Sopenharmony_ci		/* doesn't set the sample rate attribute, but supports it */
18528c2ecf20Sopenharmony_ci		fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
18538c2ecf20Sopenharmony_ci		break;
18548c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
18558c2ecf20Sopenharmony_ci	case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
18568c2ecf20Sopenharmony_ci	case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
18578c2ecf20Sopenharmony_ci	case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
18588c2ecf20Sopenharmony_ci					an older model 77d:223) */
18598c2ecf20Sopenharmony_ci	/*
18608c2ecf20Sopenharmony_ci	 * plantronics headset and Griffin iMic have set adaptive-in
18618c2ecf20Sopenharmony_ci	 * although it's really not...
18628c2ecf20Sopenharmony_ci	 */
18638c2ecf20Sopenharmony_ci		fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
18648c2ecf20Sopenharmony_ci		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
18658c2ecf20Sopenharmony_ci			fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
18668c2ecf20Sopenharmony_ci		else
18678c2ecf20Sopenharmony_ci			fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
18688c2ecf20Sopenharmony_ci		break;
18698c2ecf20Sopenharmony_ci	case USB_ID(0x07fd, 0x0004):  /* MOTU MicroBook IIc */
18708c2ecf20Sopenharmony_ci		/*
18718c2ecf20Sopenharmony_ci		 * MaxPacketsOnly attribute is erroneously set in endpoint
18728c2ecf20Sopenharmony_ci		 * descriptors. As a result this card produces noise with
18738c2ecf20Sopenharmony_ci		 * all sample rates other than 96 kHz.
18748c2ecf20Sopenharmony_ci		 */
18758c2ecf20Sopenharmony_ci		fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX;
18768c2ecf20Sopenharmony_ci		break;
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci}
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci/*
18818c2ecf20Sopenharmony_ci * registration quirk:
18828c2ecf20Sopenharmony_ci * the registration is skipped if a device matches with the given ID,
18838c2ecf20Sopenharmony_ci * unless the interface reaches to the defined one.  This is for delaying
18848c2ecf20Sopenharmony_ci * the registration until the last known interface, so that the card and
18858c2ecf20Sopenharmony_ci * devices appear at the same time.
18868c2ecf20Sopenharmony_ci */
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistruct registration_quirk {
18898c2ecf20Sopenharmony_ci	unsigned int usb_id;	/* composed via USB_ID() */
18908c2ecf20Sopenharmony_ci	unsigned int interface;	/* the interface to trigger register */
18918c2ecf20Sopenharmony_ci};
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci#define REG_QUIRK_ENTRY(vendor, product, iface) \
18948c2ecf20Sopenharmony_ci	{ .usb_id = USB_ID(vendor, product), .interface = (iface) }
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_cistatic const struct registration_quirk registration_quirks[] = {
18978c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0951, 0x16d8, 2),	/* Kingston HyperX AMP */
18988c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0951, 0x16ed, 2),	/* Kingston HyperX Cloud Alpha S */
18998c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0951, 0x16ea, 2),	/* Kingston HyperX Cloud Flight S */
19008c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x1f46, 2),	/* JBL Quantum 600 */
19018c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x1f47, 2),	/* JBL Quantum 800 */
19028c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x1f4c, 2),	/* JBL Quantum 400 */
19038c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x2039, 2),	/* JBL Quantum 400 */
19048c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x203c, 2),	/* JBL Quantum 600 */
19058c2ecf20Sopenharmony_ci	REG_QUIRK_ENTRY(0x0ecb, 0x203e, 2),	/* JBL Quantum 800 */
19068c2ecf20Sopenharmony_ci	{ 0 }					/* terminator */
19078c2ecf20Sopenharmony_ci};
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci/* return true if skipping registration */
19108c2ecf20Sopenharmony_cibool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface)
19118c2ecf20Sopenharmony_ci{
19128c2ecf20Sopenharmony_ci	const struct registration_quirk *q;
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	for (q = registration_quirks; q->usb_id; q++)
19158c2ecf20Sopenharmony_ci		if (chip->usb_id == q->usb_id)
19168c2ecf20Sopenharmony_ci			return iface < q->interface;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	/* Register as normal */
19198c2ecf20Sopenharmony_ci	return false;
19208c2ecf20Sopenharmony_ci}
1921