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