summaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 19:29:29 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 19:29:29 +0200
commit0d290223a6c77107b1c3988959e49279a8dafaba (patch)
tree2b250c9e698b84a38d17920c0712558226c93c78 /sound/usb
parentx86/setup: Explicitly include acpi.h (diff)
parentMerge tag 'asoc-v5.15' of https://git.kernel.org/pub/scm/linux/kernel/git/bro... (diff)
downloadlinux-0d290223a6c77107b1c3988959e49279a8dafaba.tar.xz
linux-0d290223a6c77107b1c3988959e49279a8dafaba.zip
Merge tag 'sound-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "There are a few intensive changes in ALSA core side at this time that helped with significant code reduction. Meanwhile we keep getting new stuff, so the total size still grows... Anyway, the below are some highlights in this development cycle. ALSA core: - New helpers to manage page allocations and card object with devres - Refactoring for memory allocation with wc-pages - A new PCM hardware flag SNDRV_PCM_INFO_EXPLICIT_SYNC for controlling the explicit sync of the stream control; it'll be used for ASoC SOF and non-coherent memory in future ASoC: - Lots of cleanups and improvements to the Intel drivers, including some new systems support - New support for AMD Vangoh, CUI CMM-4030D-261, Mediatek Mt8195, Renesas RZ/G2L Mediatek Mt8195, RealTek RT101P, Renesas RZ/G2L, Rockchip RK3568 S/PDIF USB-audio: - Re-organized the quirk handling and a new option quirk_flags - Fix for a regression in 5.14 code change for JACK - Quirks for Sony WALKMAN, Digidesign mbox HD-audio: - Enhanced support for CS8409 codec - More consistent shutdown behavior with the runtime PM - The model option can accept the PCI or codec SSID as an alias - Quirks for ASUS ROG, HP Spectre x360 Others: - Lots of code reduction in legacy drivers with devres helpers - FireWire MOTU 896HD support" * tag 'sound-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (421 commits) ASoC: Revert PCM trigger changes ALSA: usb-audio: Add lowlatency module option ALSA: hda/cs8409: Initialize Codec only in init fixup. ALSA: hda/cs8409: Ensure Type Detection is only run on startup when necessary ALSA: usb-audio: Work around for XRUN with low latency playback ALSA: pcm: fix divide error in snd_pcm_lib_ioctl ASoC: soc-pcm: test refcount before triggering ASoC: soc-pcm: protect BE dailink state changes in trigger ASoC: wcd9335: Disable irq on slave ports in the remove function ASoC: wcd9335: Fix a memory leak in the error handling path of the probe function ASoC: wcd9335: Fix a double irq free in the remove function ALSA: hda: Disable runtime resume at shutdown ASoC: rockchip: i2s: Add support for frame inversion ASoC: dt-bindings: rockchip: Add compatible strings for more SoCs ASoC: rockchip: i2s: Add compatible for more SoCs ASoC: rockchip: i2s: Make playback/capture optional ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B ASoC: dt-bindings: rockchip: Document reset property for i2s ASoC: rockchip: i2s: Fix regmap_ops hang ASoC: rockchip: i2s: Improve dma data transfer efficiency ...
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/card.c46
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/clock.c15
-rw-r--r--sound/usb/endpoint.c21
-rw-r--r--sound/usb/format.c6
-rw-r--r--sound/usb/implicit.c6
-rw-r--r--sound/usb/mixer.c10
-rw-r--r--sound/usb/mixer.h3
-rw-r--r--sound/usb/mixer_maps.c22
-rw-r--r--sound/usb/mixer_quirks.c265
-rw-r--r--sound/usb/pcm.c14
-rw-r--r--sound/usb/quirks-table.h70
-rw-r--r--sound/usb/quirks.c361
-rw-r--r--sound/usb/quirks.h5
-rw-r--r--sound/usb/stream.c4
-rw-r--r--sound/usb/usbaudio.h69
16 files changed, 553 insertions, 366 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index a1f8c3a026f5..fd570a42f043 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -68,9 +68,11 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
static bool ignore_ctl_error;
static bool autoclock = true;
+static bool lowlatency = true;
static char *quirk_alias[SNDRV_CARDS];
static char *delayed_register[SNDRV_CARDS];
static bool implicit_fb[SNDRV_CARDS];
+static unsigned int quirk_flags[SNDRV_CARDS];
bool snd_usb_use_vmalloc = true;
bool snd_usb_skip_validation;
@@ -92,12 +94,16 @@ MODULE_PARM_DESC(ignore_ctl_error,
"Ignore errors from USB controller for mixer interfaces.");
module_param(autoclock, bool, 0444);
MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");
+module_param(lowlatency, bool, 0444);
+MODULE_PARM_DESC(lowlatency, "Enable low latency playback (default: yes).");
module_param_array(quirk_alias, charp, NULL, 0444);
MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef.");
module_param_array(delayed_register, charp, NULL, 0444);
MODULE_PARM_DESC(delayed_register, "Quirk for delayed registration, given by id:iface, e.g. 0123abcd:4.");
module_param_array(implicit_fb, bool, NULL, 0444);
MODULE_PARM_DESC(implicit_fb, "Apply generic implicit feedback sync mode.");
+module_param_array(quirk_flags, uint, NULL, 0444);
+MODULE_PARM_DESC(quirk_flags, "Driver quirk bit flags.");
module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444);
MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes).");
module_param_named(skip_validation, snd_usb_skip_validation, bool, 0444);
@@ -378,6 +384,9 @@ static const struct usb_audio_device_name usb_audio_names[] = {
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
+ DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
+ DEVICE_NAME(0x05e1, 0x0480, "Hauppauge", "Woodbury"),
+
/* ASUS ROG Strix */
PROFILE_NAME(0x0b05, 0x1917,
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
@@ -406,6 +415,8 @@ static const struct usb_audio_device_name usb_audio_names[] = {
PROFILE_NAME(0x0db0, 0x543d,
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+ DEVICE_NAME(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"),
+
/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */
DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"),
DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"),
@@ -424,6 +435,22 @@ static const struct usb_audio_device_name usb_audio_names[] = {
PROFILE_NAME(0x26ce, 0x0a01,
"Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"),
+ DEVICE_NAME(0x2040, 0x7200, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7201, "Hauppauge", "HVR-950Q-MXL"),
+ DEVICE_NAME(0x2040, 0x7210, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7211, "Hauppauge", "HVR-950Q-MXL"),
+ DEVICE_NAME(0x2040, 0x7213, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7217, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x721b, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x721e, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x721f, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7240, "Hauppauge", "HVR-850"),
+ DEVICE_NAME(0x2040, 0x7260, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7280, "Hauppauge", "HVR-950Q"),
+ DEVICE_NAME(0x2040, 0x7281, "Hauppauge", "HVR-950Q-MXL"),
+ DEVICE_NAME(0x2040, 0x8200, "Hauppauge", "Woodbury"),
+
{ } /* terminator */
};
@@ -599,6 +626,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
chip->setup = device_setup[idx];
chip->generic_implicit_fb = implicit_fb[idx];
chip->autoclock = autoclock;
+ chip->lowlatency = lowlatency;
atomic_set(&chip->active, 1); /* avoid autopm during probing */
atomic_set(&chip->usage_count, 0);
atomic_set(&chip->shutdown, 0);
@@ -610,6 +638,11 @@ static int snd_usb_audio_create(struct usb_interface *intf,
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
+ if (quirk_flags[idx])
+ chip->quirk_flags = quirk_flags[idx];
+ else
+ snd_usb_init_quirk_flags(chip);
+
card->private_free = snd_usb_audio_free;
strcpy(card->driver, "USB-Audio");
@@ -781,6 +814,12 @@ static int usb_audio_probe(struct usb_interface *intf,
dev_set_drvdata(&dev->dev, chip);
+ if (ignore_ctl_error)
+ chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR;
+
+ if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
+ usb_disable_autosuspend(interface_to_usbdev(intf));
+
/*
* For devices with more than one control interface, we assume the
* first contains the audio controls. We might need a more specific
@@ -789,7 +828,6 @@ static int usb_audio_probe(struct usb_interface *intf,
if (!chip->ctrl_intf)
chip->ctrl_intf = alts;
- chip->txfr_quirk = 0;
err = 1; /* continue */
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
/* need some special handlings */
@@ -803,7 +841,7 @@ static int usb_audio_probe(struct usb_interface *intf,
err = snd_usb_create_streams(chip, ifnum);
if (err < 0)
goto __error;
- err = snd_usb_create_mixer(chip, ifnum, ignore_ctl_error);
+ err = snd_usb_create_mixer(chip, ifnum);
if (err < 0)
goto __error;
}
@@ -825,7 +863,7 @@ static int usb_audio_probe(struct usb_interface *intf,
goto __error;
}
- if (quirk && quirk->shares_media_device) {
+ if (chip->quirk_flags & QUIRK_FLAG_SHARE_MEDIA_DEVICE) {
/* don't want to fail when snd_media_device_create() fails */
snd_media_device_create(chip, intf);
}
@@ -907,7 +945,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
}
}
- if (chip->quirk_type == QUIRK_SETUP_DISABLE_AUTOSUSPEND)
+ if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
usb_enable_autosuspend(interface_to_usbdev(intf));
chip->num_interfaces--;
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 6c0a052a28f9..5b19901f305a 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -94,6 +94,7 @@ struct snd_usb_endpoint {
struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */
unsigned int nurbs; /* # urbs */
+ unsigned int nominal_queue_size; /* total buffer sizes in URBs */
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
char *syncbuf; /* sync buffer for all sync URBs */
@@ -187,6 +188,7 @@ struct snd_usb_substream {
} dsd_dop;
bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
+ bool early_playback_start; /* early start needed for playback? */
struct media_ctl *media_ctl;
};
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 14456f61539e..81d5ce07d548 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -324,11 +324,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
sources[ret - 1],
visited, validate);
if (ret > 0) {
- /*
- * For Samsung USBC Headset (AKG), setting clock selector again
- * will result in incorrect default clock setting problems
- */
- if (chip->usb_id == USB_ID(0x04e8, 0xa051))
+ /* Skip setting clock selector again for some devices */
+ if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR)
return ret;
err = uac_clock_selector_set_val(chip, entity_id, cur);
if (err < 0)
@@ -426,7 +423,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip,
/* Don't check the sample rate for devices which we know don't
* support reading */
- if (snd_usb_get_sample_rate_quirk(chip))
+ if (chip->quirk_flags & QUIRK_FLAG_GET_SAMPLE_RATE)
return 0;
/* the firmware is likely buggy, don't repeat to fail too many times */
if (chip->sample_rate_read_error > 2)
@@ -541,10 +538,8 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
*/
clock = snd_usb_clock_find_source(chip, fmt, false);
- /* Denon DN-X1600 hardcoded
- * Sample rate seems to be set on the hardware itself
- */
- if (chip->usb_id == USB_ID(0x154e, 0x500e))
+ /* Hardcoded sample rates */
+ if (chip->quirk_flags & QUIRK_FLAG_IGNORE_CLOCK_SOURCE)
return 0;
if (clock < 0)
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 4f856771216b..533919a28856 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -240,6 +240,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
call_retire_callback(ep, urb);
}
+static inline bool has_tx_length_quirk(struct snd_usb_audio *chip)
+{
+ return chip->quirk_flags & QUIRK_FLAG_TX_LENGTH;
+}
+
static void prepare_silent_urb(struct snd_usb_endpoint *ep,
struct snd_urb_ctx *ctx)
{
@@ -250,7 +255,7 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
int i;
/* For tx_length_quirk, put packet length at start of packet */
- if (ep->chip->tx_length_quirk)
+ if (has_tx_length_quirk(ep->chip))
extra = sizeof(packet_length);
for (i = 0; i < ctx->packets; ++i) {
@@ -803,7 +808,8 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
return err;
}
- snd_usb_set_interface_quirk(chip);
+ if (chip->quirk_flags & QUIRK_FLAG_IFACE_DELAY)
+ msleep(50);
return 0;
}
@@ -952,7 +958,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
unsigned int max_urbs, i;
const struct audioformat *fmt = ep->cur_audiofmt;
int frame_bits = ep->cur_frame_bytes * 8;
- int tx_length_quirk = (chip->tx_length_quirk &&
+ int tx_length_quirk = (has_tx_length_quirk(chip) &&
usb_pipeout(ep->pipe));
usb_audio_dbg(chip, "Setting params for data EP 0x%x, pipe 0x%x\n",
@@ -1126,6 +1132,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
INIT_LIST_HEAD(&u->ready_list);
}
+ /* total buffer bytes of all URBs plus the next queue;
+ * referred in pcm.c
+ */
+ ep->nominal_queue_size = maxsize * urb_packs * (ep->nurbs + 1);
return 0;
out_of_memory:
@@ -1287,6 +1297,9 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
* to be set up before parameter setups
*/
iface_first = ep->cur_audiofmt->protocol == UAC_VERSION_1;
+ /* Workaround for devices that require the interface setup at first like UAC1 */
+ if (chip->quirk_flags & QUIRK_FLAG_SET_IFACE_FIRST)
+ iface_first = true;
if (iface_first) {
err = endpoint_set_interface(chip, ep, true);
if (err < 0)
@@ -1377,7 +1390,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
goto __error;
if (snd_usb_endpoint_implicit_feedback_sink(ep) &&
- !ep->chip->playback_first) {
+ !(ep->chip->quirk_flags & QUIRK_FLAG_PLAYBACK_FIRST)) {
for (i = 0; i < ep->nurbs; i++) {
struct snd_urb_ctx *ctx = ep->urb + i;
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index eb216fef4ba7..50efccbffb8a 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -472,12 +472,8 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip,
* behavior afterwards by some unknown reason. Do this only for the
* known devices.
*/
- switch (USB_ID_VENDOR(chip->usb_id)) {
- case 0x07fd: /* MOTU */
- break;
- default:
+ if (!(chip->quirk_flags & QUIRK_FLAG_VALIDATE_RATES))
return 0; /* don't perform the validation as default */
- }
table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL);
if (!table)
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index 590a0dbba7a2..23767a14d126 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -171,7 +171,7 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip,
if (!usb_endpoint_is_isoc_in(epd) ||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
return 0;
- chip->playback_first = 1;
+ chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST;
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
alts->desc.bInterfaceNumber, alts);
}
@@ -320,7 +320,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
case IMPLICIT_FB_FIXED:
return 0; /* no quirk */
case IMPLICIT_FB_BOTH:
- chip->playback_first = 1;
+ chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST;
return add_generic_implicit_fb(chip, fmt, alts);
}
}
@@ -344,7 +344,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
/* Pioneer devices with vendor spec class */
if (is_pioneer_implicit_fb(chip, alts)) {
- chip->playback_first = 1;
+ chip->quirk_flags |= QUIRK_FLAG_PLAYBACK_FIRST;
return add_implicit_fb_sync_ep(chip, fmt,
get_endpoint(alts, 1)->bEndpointAddress,
1, alts->desc.bInterfaceNumber,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 9b713b4a5ec4..43bc59575a6e 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1572,9 +1572,9 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
static void check_no_speaker_on_headset(struct snd_kcontrol *kctl,
struct snd_card *card)
{
- const char *names_to_check[] = {
+ static const char * const names_to_check[] = {
"Headset", "headset", "Headphone", "headphone", NULL};
- const char **s;
+ const char * const *s;
bool found = false;
if (strcmp("Speaker", kctl->id.name))
@@ -3183,7 +3183,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
state.map = map->map;
state.selector_map = map->selector_map;
mixer->connector_map = map->connector_map;
- mixer->ignore_ctl_error |= map->ignore_ctl_error;
break;
}
}
@@ -3508,8 +3507,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
return 0;
}
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
- int ignore_error)
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
{
static const struct snd_device_ops dev_ops = {
.dev_free = snd_usb_mixer_dev_free
@@ -3523,7 +3521,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
if (!mixer)
return -ENOMEM;
mixer->chip = chip;
- mixer->ignore_ctl_error = ignore_error;
+ mixer->ignore_ctl_error = !!(chip->quirk_flags & QUIRK_FLAG_IGNORE_CTL_ERROR);
mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
GFP_KERNEL);
if (!mixer->id_elems) {
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index ea41e7a1f7bf..876bbc9a71ad 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -97,8 +97,7 @@ struct usb_mixer_elem_info {
void *private_data;
};
-int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
- int ignore_error);
+int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif);
void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer);
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index c5794e83fd80..55eea90ee993 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -28,7 +28,6 @@ struct usbmix_ctl_map {
const struct usbmix_name_map *map;
const struct usbmix_selector_map *selector_map;
const struct usbmix_connector_map *connector_map;
- int ignore_ctl_error;
};
/*
@@ -432,7 +431,6 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
{
.id = USB_ID(0x041e, 0x3000),
.map = extigy_map,
- .ignore_ctl_error = 1,
},
{
.id = USB_ID(0x041e, 0x3010),
@@ -452,29 +450,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.map = audigy2nx_map,
.selector_map = audigy2nx_selectors,
},
- { /* Logitech, Inc. QuickCam Pro for Notebooks */
- .id = USB_ID(0x046d, 0x0991),
- .ignore_ctl_error = 1,
- },
- { /* Logitech, Inc. QuickCam E 3500 */
- .id = USB_ID(0x046d, 0x09a4),
- .ignore_ctl_error = 1,
- },
{ /* Plantronics GameCom 780 */
.id = USB_ID(0x047f, 0xc010),
.map = gamecom780_map,
},
{
- /* Hercules DJ Console (Windows Edition) */
- .id = USB_ID(0x06f8, 0xb000),
- .ignore_ctl_error = 1,
- },
- {
- /* Hercules DJ Console (Macintosh Edition) */
- .id = USB_ID(0x06f8, 0xd002),
- .ignore_ctl_error = 1,
- },
- {
/* Hercules Gamesurround Muse Pocket LT
* (USB 5.1 Channel Audio Adapter)
*/
@@ -492,7 +472,6 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
{
.id = USB_ID(0x08bb, 0x2702),
.map = linex_map,
- .ignore_ctl_error = 1,
},
{
.id = USB_ID(0x0a92, 0x0091),
@@ -517,7 +496,6 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
{
.id = USB_ID(0x13e5, 0x0001),
.map = scratch_live_map,
- .ignore_ctl_error = 1,
},
{
.id = USB_ID(0x200c, 0x1018),
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 0a3cb8fd7d00..a66ce0375fd9 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -594,85 +594,208 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
&snd_xonar_u1_output_switch, NULL);
}
+/* Digidesign Mbox 1 helper functions */
+
+static int snd_mbox1_is_spdif_synced(struct snd_usb_audio *chip)
+{
+ unsigned char buff[3];
+ int err;
+ int is_spdif_synced;
+
+ /* Read clock source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ return err;
+
+ /* spdif sync: buff is all zeroes */
+ is_spdif_synced = !(buff[0] | buff[1] | buff[2]);
+ return is_spdif_synced;
+}
+
+static int snd_mbox1_set_clk_source(struct snd_usb_audio *chip, int rate_or_zero)
+{
+ /* 2 possibilities: Internal -> expects sample rate
+ * S/PDIF sync -> expects rate = 0
+ */
+ unsigned char buff[3];
+
+ buff[0] = (rate_or_zero >> 0) & 0xff;
+ buff[1] = (rate_or_zero >> 8) & 0xff;
+ buff[2] = (rate_or_zero >> 16) & 0xff;
+
+ /* Set clock source */
+ return snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x1,
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+}
+
+static int snd_mbox1_is_spdif_input(struct snd_usb_audio *chip)
+{
+ /* Hardware gives 2 possibilities: ANALOG Source -> 0x01
+ * S/PDIF Source -> 0x02
+ */
+ int err;
+ unsigned char source[1];
+
+ /* Read input source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0x00, 0x500, source, 1);
+ if (err < 0)
+ return err;
+
+ return (source[0] == 2);
+}
+
+static int snd_mbox1_set_input_source(struct snd_usb_audio *chip, int is_spdif)
+{
+ /* NB: Setting the input source to S/PDIF resets the clock source to S/PDIF
+ * Hardware expects 2 possibilities: ANALOG Source -> 0x01
+ * S/PDIF Source -> 0x02
+ */
+ unsigned char buff[1];
+
+ buff[0] = (is_spdif & 1) + 1;
+
+ /* Set input source */
+ return snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x1,
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
+}
+
/* Digidesign Mbox 1 clock source switch (internal/spdif) */
-static int snd_mbox1_switch_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_mbox1_clk_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ struct snd_usb_audio *chip = list->mixer->chip;
+ int err;
+
+ err = snd_usb_lock_shutdown(chip);
+ if (err < 0)
+ goto err;
+
+ err = snd_mbox1_is_spdif_synced(chip);
+ if (err < 0)
+ goto err;
+
+ kctl->private_value = err;
+ err = 0;
ucontrol->value.enumerated.item[0] = kctl->private_value;
- return 0;
+err:
+ snd_usb_unlock_shutdown(chip);
+ return err;
}
-static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val)
+static int snd_mbox1_clk_switch_update(struct usb_mixer_interface *mixer, int is_spdif_sync)
{
struct snd_usb_audio *chip = mixer->chip;
int err;
- unsigned char buff[3];
err = snd_usb_lock_shutdown(chip);
if (err < 0)
return err;
- /* Prepare for magic command to toggle clock source */
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), 0x81,
- USB_DIR_IN |
- USB_TYPE_CLASS |
- USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
+ err = snd_mbox1_is_spdif_input(chip);
if (err < 0)
goto err;
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), 0x81,
- USB_DIR_IN |
- USB_TYPE_CLASS |
- USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+
+ err = snd_mbox1_is_spdif_synced(chip);
if (err < 0)
goto err;
- /* 2 possibilities: Internal -> send sample rate
- * S/PDIF sync -> send zeroes
- * NB: Sample rate locked to 48kHz on purpose to
- * prevent user from resetting the sample rate
- * while S/PDIF sync is enabled and confusing
- * this configuration.
- */
- if (val == 0) {
- buff[0] = 0x80;
- buff[1] = 0xbb;
- buff[2] = 0x00;
- } else {
- buff[0] = buff[1] = buff[2] = 0x00;
- }
+ /* FIXME: hardcoded sample rate */
+ err = snd_mbox1_set_clk_source(chip, is_spdif_sync ? 0 : 48000);
+ if (err < 0)
+ goto err;
- /* Send the magic command to toggle the clock source */
- err = snd_usb_ctl_msg(chip->dev,
- usb_sndctrlpipe(chip->dev, 0), 0x1,
- USB_TYPE_CLASS |
- USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ err = snd_mbox1_is_spdif_synced(chip);
+err:
+ snd_usb_unlock_shutdown(chip);
+ return err;
+}
+
+static int snd_mbox1_clk_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ struct usb_mixer_interface *mixer = list->mixer;
+ int err;
+ bool cur_val, new_val;
+
+ cur_val = kctl->private_value;
+ new_val = ucontrol->value.enumerated.item[0];
+ if (cur_val == new_val)
+ return 0;
+
+ kctl->private_value = new_val;
+ err = snd_mbox1_clk_switch_update(mixer, new_val);
+ return err < 0 ? err : 1;
+}
+
+static int snd_mbox1_clk_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *const texts[2] = {
+ "Internal",
+ "S/PDIF"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int snd_mbox1_clk_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_mbox1_clk_switch_update(list->mixer, list->kctl->private_value);
+}
+
+/* Digidesign Mbox 1 input source switch (analog/spdif) */
+
+static int snd_mbox1_src_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kctl->private_value;
+ return 0;
+}
+
+static int snd_mbox1_src_switch_update(struct usb_mixer_interface *mixer, int is_spdif_input)
+{
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
+
+ err = snd_usb_lock_shutdown(chip);
+ if (err < 0)
+ return err;
+
+ err = snd_mbox1_is_spdif_input(chip);
if (err < 0)
goto err;
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), 0x81,
- USB_DIR_IN |
- USB_TYPE_CLASS |
- USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+
+ err = snd_mbox1_set_input_source(chip, is_spdif_input);
if (err < 0)
goto err;
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), 0x81,
- USB_DIR_IN |
- USB_TYPE_CLASS |
- USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3);
+
+ err = snd_mbox1_is_spdif_input(chip);
if (err < 0)
goto err;
+ err = snd_mbox1_is_spdif_synced(chip);
err:
snd_usb_unlock_shutdown(chip);
return err;
}
-static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_mbox1_src_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
struct usb_mixer_interface *mixer = list->mixer;
@@ -685,42 +808,60 @@ static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
return 0;
kctl->private_value = new_val;
- err = snd_mbox1_switch_update(mixer, new_val);
+ err = snd_mbox1_src_switch_update(mixer, new_val);
return err < 0 ? err : 1;
}
-static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int snd_mbox1_src_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
static const char *const texts[2] = {
- "Internal",
+ "Analog",
"S/PDIF"
};
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
-static int snd_mbox1_switch_resume(struct usb_mixer_elem_list *list)
+static int snd_mbox1_src_switch_resume(struct usb_mixer_elem_list *list)
{
- return snd_mbox1_switch_update(list->mixer, list->kctl->private_value);
+ return snd_mbox1_src_switch_update(list->mixer, list->kctl->private_value);
}
-static const struct snd_kcontrol_new snd_mbox1_switch = {
+static const struct snd_kcontrol_new snd_mbox1_clk_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Clock Source",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_mbox1_switch_info,
- .get = snd_mbox1_switch_get,
- .put = snd_mbox1_switch_put,
+ .info = snd_mbox1_clk_switch_info,
+ .get = snd_mbox1_clk_switch_get,
+ .put = snd_mbox1_clk_switch_put,
+ .private_value = 0
+};
+
+static const struct snd_kcontrol_new snd_mbox1_src_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .index = 1,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_mbox1_src_switch_info,
+ .get = snd_mbox1_src_switch_get,
+ .put = snd_mbox1_src_switch_put,
.private_value = 0
};
-static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer)
+static int snd_mbox1_controls_create(struct usb_mixer_interface *mixer)
{
- return add_single_ctl_with_resume(mixer, 0,
- snd_mbox1_switch_resume,
- &snd_mbox1_switch, NULL);
+ int err;
+ err = add_single_ctl_with_resume(mixer, 0,
+ snd_mbox1_clk_switch_resume,
+ &snd_mbox1_clk_switch, NULL);
+ if (err < 0)
+ return err;
+
+ return add_single_ctl_with_resume(mixer, 1,
+ snd_mbox1_src_switch_resume,
+ &snd_mbox1_src_switch, NULL);
}
/* Native Instruments device quirks */
@@ -3029,7 +3170,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
break;
case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */
- err = snd_mbox1_create_sync_switch(mixer);
+ err = snd_mbox1_controls_create(mixer);
break;
case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 4e5031a68064..5dc9266180e3 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -614,6 +614,15 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->period_elapsed_pending = 0;
runtime->delay = 0;
+ /* check whether early start is needed for playback stream */
+ subs->early_playback_start =
+ subs->direction == SNDRV_PCM_STREAM_PLAYBACK &&
+ (!chip->lowlatency ||
+ (subs->data_endpoint->nominal_queue_size >= subs->buffer_bytes));
+
+ if (subs->early_playback_start)
+ ret = start_endpoints(subs);
+
unlock:
snd_usb_unlock_shutdown(chip);
return ret;
@@ -1394,7 +1403,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
subs->trigger_tstamp_pending_update = false;
}
- if (period_elapsed && !subs->running) {
+ if (period_elapsed && !subs->running && !subs->early_playback_start) {
subs->period_elapsed_pending = 1;
period_elapsed = 0;
}
@@ -1448,7 +1457,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
prepare_playback_urb,
retire_playback_urb,
subs);
- if (cmd == SNDRV_PCM_TRIGGER_START) {
+ if (!subs->early_playback_start &&
+ cmd == SNDRV_PCM_TRIGGER_START) {
err = start_endpoints(subs);
if (err < 0) {
snd_usb_endpoint_set_callback(subs->data_endpoint,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 19bb499c17da..e03043f7dad3 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2730,23 +2730,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
-/* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
-{
- USB_DEVICE(0x17aa, 0x1046),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
- }
-},
-/* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
-{
- USB_DEVICE(0x17aa, 0x104d),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
- }
-},
-
/* Native Instruments MK2 series */
{
/* Komplete Audio 6 */
@@ -2802,53 +2785,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
-/*
- * Auvitek au0828 devices with audio interface.
- * This should be kept in sync with drivers/media/usb/au0828/au0828-cards.c
- * Please notice that some drivers are DVB only, and don't need to be
- * here. That's the case, for example, of DVICO_FUSIONHDTV7.
- */
-
-#define AU0828_DEVICE(vid, pid, vname, pname) { \
- USB_AUDIO_DEVICE(vid, pid), \
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { \
- .vendor_name = vname, \
- .product_name = pname, \
- .ifnum = QUIRK_ANY_INTERFACE, \
- .type = QUIRK_AUDIO_ALIGN_TRANSFER, \
- .shares_media_device = 1, \
- } \
-}
-
-AU0828_DEVICE(0x2040, 0x7200, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7240, "Hauppauge", "HVR-850"),
-AU0828_DEVICE(0x2040, 0x7210, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7217, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x721b, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x721e, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x721f, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7280, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7201, "Hauppauge", "HVR-950Q-MXL"),
-AU0828_DEVICE(0x2040, 0x7211, "Hauppauge", "HVR-950Q-MXL"),
-AU0828_DEVICE(0x2040, 0x7281, "Hauppauge", "HVR-950Q-MXL"),
-AU0828_DEVICE(0x05e1, 0x0480, "Hauppauge", "Woodbury"),
-AU0828_DEVICE(0x2040, 0x8200, "Hauppauge", "Woodbury"),
-AU0828_DEVICE(0x2040, 0x7260, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7213, "Hauppauge", "HVR-950Q"),
-AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
-
-/* Syntek STK1160 */
-{
- USB_AUDIO_DEVICE(0x05e1, 0x0408),
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Syntek",
- .product_name = "STK1160",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER
- }
-},
-
/* Digidesign Mbox */
{
/* Thanks to Clemens Ladisch <clemens@ladisch.de> */
@@ -3811,7 +3747,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
* MacroSilicon MS2109 based HDMI capture cards
*
* These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
- * They also need QUIRK_AUDIO_ALIGN_TRANSFER, which makes one wonder if
+ * They also need QUIRK_FLAG_ALIGN_TRANSFER, which makes one wonder if
* they pretend to be 96kHz mono as a workaround for stereo being broken
* by that...
*
@@ -3828,10 +3764,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.data = &(const struct snd_usb_audio_quirk[]) {
{
.ifnum = 2,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- },
- {
- .ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_MIXER,
},
{
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 326d1b0ea5e6..4479a590194f 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -75,19 +75,6 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip,
}
-/*
- * Allow alignment on audio sub-slot (channel samples) rather than
- * on audio slots (audio frames)
- */
-static int create_align_transfer_quirk(struct snd_usb_audio *chip,
- struct usb_interface *iface,
- struct usb_driver *driver,
- const struct snd_usb_audio_quirk *quirk)
-{
- chip->txfr_quirk = 1;
- return 1; /* Continue with creating streams and mixer */
-}
-
static int create_any_midi_quirk(struct snd_usb_audio *chip,
struct usb_interface *intf,
struct usb_driver *driver,
@@ -108,9 +95,6 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd;
int err;
- if (chip->usb_id == USB_ID(0x1686, 0x00dd)) /* Zoom R16/24 */
- chip->tx_length_quirk = 1;
-
alts = &iface->altsetting[0];
altsd = get_iface_desc(alts);
err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
@@ -547,16 +531,7 @@ static int create_standard_mixer_quirk(struct snd_usb_audio *chip,
if (quirk->ifnum < 0)
return 0;
- return snd_usb_create_mixer(chip, quirk->ifnum, 0);
-}
-
-static int setup_disable_autosuspend(struct snd_usb_audio *chip,
- struct usb_interface *iface,
- struct usb_driver *driver,
- const struct snd_usb_audio_quirk *quirk)
-{
- usb_disable_autosuspend(interface_to_usbdev(iface));
- return 1; /* Continue with creating streams and mixer */
+ return snd_usb_create_mixer(chip, quirk->ifnum);
}
/*
@@ -595,9 +570,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
- [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
- [QUIRK_SETUP_DISABLE_AUTOSUSPEND] = setup_disable_autosuspend,
};
if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -1518,62 +1491,13 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
-bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
-{
- /* devices which do not support reading the sample rate. */
- switch (chip->usb_id) {
- case USB_ID(0x041e, 0x4080): /* Creative Live Cam VF0610 */
- case USB_ID(0x04d8, 0xfeea): /* Benchmark DAC1 Pre */
- case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
- case USB_ID(0x05a3, 0x9420): /* ELP HD USB Camera */
- case USB_ID(0x05a7, 0x1020): /* Bose Companion 5 */
- case USB_ID(0x074d, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
- case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
- case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
- case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
- case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
- case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
- case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */
- return true;
- }
-
- /* devices of these vendors don't support reading rate, either */
- switch (USB_ID_VENDOR(chip->usb_id)) {
- case 0x045e: /* MS Lifecam */
- case 0x047f: /* Plantronics */
- case 0x1de7: /* Phoenix Audio */
- return true;
- }
-
- return false;
-}
-
-/* ITF-USB DSD based DACs need a vendor cmd to switch
- * between PCM and native DSD mode
- */
-static bool is_itf_usb_dsd_dac(unsigned int id)
-{
- switch (id) {
- case USB_ID(0x154e, 0x1002): /* Denon DCD-1500RE */
- case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
- case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
- case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
- case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */
- case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
- case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
- case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
- return true;
- }
- return false;
-}
-
int snd_usb_select_mode_quirk(struct snd_usb_audio *chip,
const struct audioformat *fmt)
{
struct usb_device *dev = chip->dev;
int err;
- if (is_itf_usb_dsd_dac(chip->usb_id)) {
+ if (chip->quirk_flags & QUIRK_FLAG_ITF_USB_DSD_DAC) {
/* First switch to alt set 0, otherwise the mode switch cmd
* will not be accepted by the DAC
*/
@@ -1636,22 +1560,6 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
ep->tenor_fb_quirk = 1;
}
-void snd_usb_set_interface_quirk(struct snd_usb_audio *chip)
-{
- if (!chip)
- return;
- /*
- * "Playback Design" products need a 50ms delay after setting the
- * USB interface.
- */
- switch (USB_ID_VENDOR(chip->usb_id)) {
- case 0x23ba: /* Playback Design */
- case 0x0644: /* TEAC Corp. */
- msleep(50);
- break;
- }
-}
-
/* quirk applied after snd_usb_ctl_msg(); not applied during boot quirks */
void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value,
@@ -1659,57 +1567,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
{
struct snd_usb_audio *chip = dev_get_drvdata(&dev->dev);
- if (!chip)
+ if (!chip || (requesttype & USB_TYPE_MASK) != USB_TYPE_CLASS)
return;
- /*
- * "Playback Design" products need a 20ms delay after each
- * class compliant request
- */
- if (USB_ID_VENDOR(chip->usb_id) == 0x23ba &&
- (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- msleep(20);
-
- /*
- * "TEAC Corp." products need a 20ms delay after each
- * class compliant request
- */
- if (USB_ID_VENDOR(chip->usb_id) == 0x0644 &&
- (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- msleep(20);
-
- /* ITF-USB DSD based DACs functionality need a delay
- * after each class compliant request
- */
- if (is_itf_usb_dsd_dac(chip->usb_id)
- && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- msleep(20);
- /*
- * Plantronics headsets (C320, C320-M, etc) need a delay to avoid
- * random microhpone failures.
- */
- if (USB_ID_VENDOR(chip->usb_id) == 0x047f &&
- (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY)
msleep(20);
-
- /* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950),
- * Jabra 550a, Kingston HyperX needs a tiny delay here,
- * otherwise requests like get/set frequency return
- * as failed despite actually succeeding.
- */
- if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
- USB_ID_VENDOR(chip->usb_id) == 0x046d || /* Logitech */
- chip->usb_id == USB_ID(0x0b0e, 0x0349) ||
- chip->usb_id == USB_ID(0x0951, 0x16ad)) &&
- (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ else if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY_1M)
usleep_range(1000, 2000);
-
- /*
- * Samsung USBC Headset (AKG) need a tiny delay after each
- * class compliant request. (Model number: AAM625R or AAM627R)
- */
- if (chip->usb_id == USB_ID(0x04e8, 0xa051) &&
- (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ else if (chip->quirk_flags & QUIRK_FLAG_CTL_MSG_DELAY_5M)
usleep_range(5000, 6000);
}
@@ -1796,7 +1661,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
}
/* ITF-USB DSD based DACs */
- if (is_itf_usb_dsd_dac(chip->usb_id)) {
+ if (chip->quirk_flags & QUIRK_FLAG_ITF_USB_DSD_DAC) {
iface = usb_ifnum_to_if(chip->dev, fp->iface);
/* Altsetting 2 support native DSD if the num of altsets is
@@ -1808,29 +1673,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
}
- /* Mostly generic method to detect many DSD-capable implementations -
- * from XMOS/Thesycon
- */
- switch (USB_ID_VENDOR(chip->usb_id)) {
- case 0x152a: /* Thesycon devices */
- case 0x20b1: /* XMOS based devices */
- case 0x22d9: /* Oppo */
- case 0x23ba: /* Playback Designs */
- case 0x25ce: /* Mytek devices */
- case 0x278b: /* Rotel? */
- case 0x292b: /* Gustard/Ess based devices */
- case 0x2972: /* FiiO devices */
- case 0x2ab6: /* T+A devices */
- case 0x3353: /* Khadas devices */
- case 0x3842: /* EVGA */
- case 0xc502: /* HiBy devices */
- if (fp->dsd_raw)
- return SNDRV_PCM_FMTBIT_DSD_U32_BE;
- break;
- default:
- break;
-
- }
+ /* Mostly generic method to detect many DSD-capable implementations */
+ if ((chip->quirk_flags & QUIRK_FLAG_DSD_RAW) && fp->dsd_raw)
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
return 0;
}
@@ -1916,3 +1761,189 @@ bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface)
/* Register as normal */
return false;
}
+
+/*
+ * driver behavior quirk flags
+ */
+struct usb_audio_quirk_flags_table {
+ u32 id;
+ u32 flags;
+};
+
+#define DEVICE_FLG(vid, pid, _flags) \
+ { .id = USB_ID(vid, pid), .flags = (_flags) }
+#define VENDOR_FLG(vid, _flags) DEVICE_FLG(vid, 0, _flags)
+
+static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ /* Device matches */
+ DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */
+ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x046d, 0x0991, /* Logitech QuickCam Pro */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x04d8, 0xfeea, /* Benchmark DAC1 Pre */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x04e8, 0xa051, /* Samsung USBC Headset (AKG) */
+ QUIRK_FLAG_SKIP_CLOCK_SELECTOR | QUIRK_FLAG_CTL_MSG_DELAY_5M),
+ DEVICE_FLG(0x054c, 0x0b8c, /* Sony WALKMAN NW-A45 DAC */
+ QUIRK_FLAG_SET_IFACE_FIRST),
+ DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x05a3, 0x9420, /* ELP HD USB Camera */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x05a7, 0x1020, /* Bose Companion 5 */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x05e1, 0x0408, /* Syntek STK1160 */
+ QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x05e1, 0x0480, /* Hauppauge Woodbury */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x0644, 0x8043, /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
+ QUIRK_FLAG_IFACE_DELAY),
+ DEVICE_FLG(0x0644, 0x8044, /* Esoteric D-05X */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
+ QUIRK_FLAG_IFACE_DELAY),
+ DEVICE_FLG(0x0644, 0x804a, /* TEAC UD-301 */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
+ QUIRK_FLAG_IFACE_DELAY),
+ DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x074d, 0x3553, /* Outlaw RR2150 (Micronas UAC3553B) */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x154e, 0x1003, /* Denon DA-300USB */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x154e, 0x3005, /* Marantz HD-DAC1 */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x154e, 0x3006, /* Marantz SA-14S1 */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x154e, 0x500e, /* Denon DN-X1600 */
+ QUIRK_FLAG_IGNORE_CLOCK_SOURCE),
+ DEVICE_FLG(0x1686, 0x00dd, /* Zoom R16/24 */
+ QUIRK_FLAG_TX_LENGTH | QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x17aa, 0x1046, /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
+ QUIRK_FLAG_DISABLE_AUTOSUSPEND),
+ DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
+ QUIRK_FLAG_DISABLE_AUTOSUSPEND),
+ DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */
+ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
+ DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7210, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7211, /* Hauppauge HVR-950Q-MXL */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7213, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7217, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x721b, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x721e, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x721f, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7240, /* Hauppauge HVR-850 */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7260, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7270, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7280, /* Hauppauge HVR-950Q */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x7281, /* Hauppauge HVR-950Q-MXL */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x2040, 0x8200, /* Hauppauge Woodbury */
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x21b4, 0x0081, /* AudioQuest DragonFly */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
+ QUIRK_FLAG_ALIGN_TRANSFER),
+
+ /* Vendor matches */
+ VENDOR_FLG(0x045e, /* MS Lifecam */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ VENDOR_FLG(0x046d, /* Logitech */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ VENDOR_FLG(0x047f, /* Plantronics */
+ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY),
+ VENDOR_FLG(0x0644, /* TEAC Corp. */
+ QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY),
+ VENDOR_FLG(0x07fd, /* MOTU */
+ QUIRK_FLAG_VALIDATE_RATES),
+ VENDOR_FLG(0x152a, /* Thesycon devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x1de7, /* Phoenix Audio */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
+ VENDOR_FLG(0x20b1, /* XMOS based devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x22d9, /* Oppo */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x23ba, /* Playback Design */
+ QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY |
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x25ce, /* Mytek devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x278b, /* Rotel? */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x292b, /* Gustard/Ess based devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x2972, /* FiiO devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x2ab6, /* T+A devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x3353, /* Khadas devices */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0x3842, /* EVGA */
+ QUIRK_FLAG_DSD_RAW),
+ VENDOR_FLG(0xc502, /* HiBy devices */
+ QUIRK_FLAG_DSD_RAW),
+
+ {} /* terminator */
+};
+
+void snd_usb_init_quirk_flags(struct snd_usb_audio *chip)
+{
+ const struct usb_audio_quirk_flags_table *p;
+
+ for (p = quirk_flags_table; p->id; p++) {
+ if (chip->usb_id == p->id ||
+ (!USB_ID_PRODUCT(p->id) &&
+ USB_ID_VENDOR(chip->usb_id) == USB_ID_VENDOR(p->id))) {
+ usb_audio_dbg(chip,
+ "Set quirk_flags 0x%x for device %04x:%04x\n",
+ p->flags, USB_ID_VENDOR(chip->usb_id),
+ USB_ID_PRODUCT(chip->usb_id));
+ chip->quirk_flags |= p->flags;
+ return;
+ }
+ }
+}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 67a02303c820..31abb7cb01a5 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -28,14 +28,11 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
const struct audioformat *fmt);
-bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip);
-
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
const struct audioformat *fp);
void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
-void snd_usb_set_interface_quirk(struct snd_usb_audio *chip);
void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value,
__u16 index, void *data, __u16 size);
@@ -53,4 +50,6 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface);
+void snd_usb_init_quirk_flags(struct snd_usb_audio *chip);
+
#endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index ee9aa1dcf0d8..ceb93d798182 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -89,8 +89,8 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
subs->stream = as;
subs->direction = stream;
subs->dev = as->chip->dev;
- subs->txfr_quirk = as->chip->txfr_quirk;
- subs->tx_length_quirk = as->chip->tx_length_quirk;
+ subs->txfr_quirk = !!(as->chip->quirk_flags & QUIRK_FLAG_ALIGN_TRANSFER);
+ subs->tx_length_quirk = !!(as->chip->quirk_flags & QUIRK_FLAG_TX_LENGTH);
subs->speed = snd_usb_get_speed(subs->dev);
subs->pkt_offset_adj = 0;
subs->stream_offset_adj = 0;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 538831cbd925..167834133b9b 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -34,10 +34,8 @@ struct snd_usb_audio {
atomic_t shutdown;
atomic_t usage_count;
wait_queue_head_t shutdown_wait;
- unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
- unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
+ unsigned int quirk_flags;
unsigned int need_delayed_register:1; /* warn for delayed registration */
- unsigned int playback_first:1; /* for implicit fb: don't wait for the first capture URBs */
int num_interfaces;
int num_suspended_intf;
int sample_rate_read_error;
@@ -57,6 +55,7 @@ struct snd_usb_audio {
bool generic_implicit_fb; /* from the 'implicit_fb' module param */
bool autoclock; /* from the 'autoclock' module param */
+ bool lowlatency; /* from the 'lowlatency' module param */
struct usb_host_interface *ctrl_intf; /* the audio control interface */
struct media_device *media_dev;
struct media_intf_devnode *ctl_intf_media_devnode;
@@ -102,10 +101,7 @@ enum quirk_type {
QUIRK_AUDIO_STANDARD_INTERFACE,
QUIRK_AUDIO_FIXED_ENDPOINT,
QUIRK_AUDIO_EDIROL_UAXX,
- QUIRK_AUDIO_ALIGN_TRANSFER,
QUIRK_AUDIO_STANDARD_MIXER,
- QUIRK_SETUP_FMT_AFTER_RESUME,
- QUIRK_SETUP_DISABLE_AUTOSUSPEND,
QUIRK_TYPE_COUNT
};
@@ -115,7 +111,6 @@ struct snd_usb_audio_quirk {
const char *product_name;
int16_t ifnum;
uint16_t type;
- bool shares_media_device;
const void *data;
};
@@ -129,4 +124,64 @@ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip);
extern bool snd_usb_use_vmalloc;
extern bool snd_usb_skip_validation;
+/*
+ * Driver behavior quirk flags, stored in chip->quirk_flags
+ *
+ * QUIRK_FLAG_GET_SAMPLE_RATE:
+ * Skip reading sample rate for devices, as some devices behave inconsistently
+ * or return error
+ * QUIRK_FLAG_SHARE_MEDIA_DEVICE:
+ * Create Media Controller API entries
+ * QUIRK_FLAG_ALIGN_TRANSFER:
+ * Allow alignment on audio sub-slot (channel samples) rather than on audio
+ * slots (audio frames)
+ * QUIRK_TX_LENGTH:
+ * Add length specifier to transfers
+ * QUIRK_FLAG_PLAYBACK_FIRST:
+ * Start playback stream at first even in implement feedback mode
+ * QUIRK_FLAG_SKIP_CLOCK_SELECTOR:
+ * Skip clock selector setup; the device may reset to invalid state
+ * QUIRK_FLAG_IGNORE_CLOCK_SOURCE:
+ * Ignore errors from clock source search; i.e. hardcoded clock
+ * QUIRK_FLAG_ITF_USB_DSD_DAC:
+ * Indicates the device is for ITF-USB DSD based DACs that need a vendor cmd
+ * to switch between PCM and native DSD mode
+ * QUIRK_FLAG_CTL_MSG_DELAY:
+ * Add a delay of 20ms at each control message handling
+ * QUIRK_FLAG_CTL_MSG_DELAY_1M:
+ * Add a delay of 1-2ms at each control message handling
+ * QUIRK_FLAG_CTL_MSG_DELAY_5M:
+ * Add a delay of 5-6ms at each control message handling
+ * QUIRK_FLAG_IFACE_DELAY:
+ * Add a delay of 50ms at each interface setup
+ * QUIRK_FLAG_VALIDATE_RATES:
+ * Perform sample rate validations at probe
+ * QUIRK_FLAG_DISABLE_AUTOSUSPEND:
+ * Disable runtime PM autosuspend
+ * QUIRK_FLAG_IGNORE_CTL_ERROR:
+ * Ignore errors for mixer access
+ * QUIRK_FLAG_DSD_RAW:
+ * Support generic DSD raw U32_BE format
+ * QUIRK_FLAG_SET_IFACE_FIRST:
+ * Set up the interface at first like UAC1
+ */
+
+#define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0)
+#define QUIRK_FLAG_SHARE_MEDIA_DEVICE (1U << 1)
+#define QUIRK_FLAG_ALIGN_TRANSFER (1U << 2)
+#define QUIRK_FLAG_TX_LENGTH (1U << 3)
+#define QUIRK_FLAG_PLAYBACK_FIRST (1U << 4)
+#define QUIRK_FLAG_SKIP_CLOCK_SELECTOR (1U << 5)
+#define QUIRK_FLAG_IGNORE_CLOCK_SOURCE (1U << 6)
+#define QUIRK_FLAG_ITF_USB_DSD_DAC (1U << 7)
+#define QUIRK_FLAG_CTL_MSG_DELAY (1U << 8)
+#define QUIRK_FLAG_CTL_MSG_DELAY_1M (1U << 9)
+#define QUIRK_FLAG_CTL_MSG_DELAY_5M (1U << 10)
+#define QUIRK_FLAG_IFACE_DELAY (1U << 11)
+#define QUIRK_FLAG_VALIDATE_RATES (1U << 12)
+#define QUIRK_FLAG_DISABLE_AUTOSUSPEND (1U << 13)
+#define QUIRK_FLAG_IGNORE_CTL_ERROR (1U << 14)
+#define QUIRK_FLAG_DSD_RAW (1U << 15)
+#define QUIRK_FLAG_SET_IFACE_FIRST (1U << 16)
+
#endif /* __USBAUDIO_H */