diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 46 | ||||
-rw-r--r-- | sound/usb/card.h | 2 | ||||
-rw-r--r-- | sound/usb/clock.c | 15 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 21 | ||||
-rw-r--r-- | sound/usb/format.c | 6 | ||||
-rw-r--r-- | sound/usb/implicit.c | 6 | ||||
-rw-r--r-- | sound/usb/mixer.c | 10 | ||||
-rw-r--r-- | sound/usb/mixer.h | 3 | ||||
-rw-r--r-- | sound/usb/mixer_maps.c | 22 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 265 | ||||
-rw-r--r-- | sound/usb/pcm.c | 14 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 70 | ||||
-rw-r--r-- | sound/usb/quirks.c | 361 | ||||
-rw-r--r-- | sound/usb/quirks.h | 5 | ||||
-rw-r--r-- | sound/usb/stream.c | 4 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 69 |
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 */ |