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