diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/Makefile | 3 | ||||
-rw-r--r-- | sound/usb/card.c | 35 | ||||
-rw-r--r-- | sound/usb/card.h | 7 | ||||
-rw-r--r-- | sound/usb/clock.c | 150 | ||||
-rw-r--r-- | sound/usb/clock.h | 4 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 247 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 1 | ||||
-rw-r--r-- | sound/usb/format.c | 52 | ||||
-rw-r--r-- | sound/usb/helper.h | 4 | ||||
-rw-r--r-- | sound/usb/line6/capture.c | 2 | ||||
-rw-r--r-- | sound/usb/line6/driver.c | 4 | ||||
-rw-r--r-- | sound/usb/line6/midibuf.c | 2 | ||||
-rw-r--r-- | sound/usb/line6/playback.c | 2 | ||||
-rw-r--r-- | sound/usb/line6/podhd.c | 22 | ||||
-rw-r--r-- | sound/usb/midi.c | 17 | ||||
-rw-r--r-- | sound/usb/mixer.c | 737 | ||||
-rw-r--r-- | sound/usb/mixer.h | 19 | ||||
-rw-r--r-- | sound/usb/mixer_maps.c | 85 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 16 | ||||
-rw-r--r-- | sound/usb/pcm.c | 55 | ||||
-rw-r--r-- | sound/usb/power.c | 2 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 305 | ||||
-rw-r--r-- | sound/usb/quirks.c | 157 | ||||
-rw-r--r-- | sound/usb/quirks.h | 7 | ||||
-rw-r--r-- | sound/usb/stream.c | 26 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 5 | ||||
-rw-r--r-- | sound/usb/usx2y/usX2Yhwdep.c | 2 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2yaudio.c | 2 | ||||
-rw-r--r-- | sound/usb/validate.c | 331 |
29 files changed, 1710 insertions, 591 deletions
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e1ce257ab705..d27a21b0ff9c 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \ power.o \ proc.o \ quirks.o \ - stream.o + stream.o \ + validate.o snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o diff --git a/sound/usb/card.c b/sound/usb/card.c index db91dc76cc91..230d862cfa3a 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -597,6 +597,10 @@ static int usb_audio_probe(struct usb_interface *intf, } } if (! chip) { + err = snd_usb_apply_boot_quirk_once(dev, intf, quirk, id); + if (err < 0) + goto __error; + /* it's a fresh one. * now look for an empty slot and create a new card instance */ @@ -655,10 +659,14 @@ static int usb_audio_probe(struct usb_interface *intf, goto __error; } - /* we are allowed to call snd_card_register() many times */ - err = snd_card_register(chip->card); - if (err < 0) - goto __error; + /* we are allowed to call snd_card_register() many times, but first + * check to see if a device needs to skip it or do anything special + */ + if (!snd_usb_registration_quirk(chip, ifnum)) { + err = snd_card_register(chip->card); + if (err < 0) + goto __error; + } if (quirk && quirk->shares_media_device) { /* don't want to fail when snd_media_device_create() fails */ @@ -806,9 +814,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) if (chip == (void *)-1L) return 0; - chip->autosuspended = !!PMSG_IS_AUTO(message); - if (!chip->autosuspended) - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); if (!chip->num_suspended_intf++) { list_for_each_entry(as, &chip->pcm_list, list) { snd_usb_pcm_suspend(as); @@ -821,6 +826,11 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) snd_usb_mixer_suspend(mixer); } + if (!PMSG_IS_AUTO(message) && !chip->system_suspend) { + snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + chip->system_suspend = chip->num_suspended_intf; + } + return 0; } @@ -834,10 +844,10 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) if (chip == (void *)-1L) return 0; - if (--chip->num_suspended_intf) - return 0; atomic_inc(&chip->active); /* avoid autopm */ + if (chip->num_suspended_intf > 1) + goto out; list_for_each_entry(as, &chip->pcm_list, list) { err = snd_usb_pcm_resume(as); @@ -859,9 +869,12 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) snd_usbmidi_resume(p); } - if (!chip->autosuspended) + out: + if (chip->num_suspended_intf == chip->system_suspend) { snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); - chip->autosuspended = 0; + chip->system_suspend = 0; + } + chip->num_suspended_intf--; err_out: atomic_dec(&chip->active); /* allow autopm after this point */ diff --git a/sound/usb/card.h b/sound/usb/card.h index 2991b9986f66..5351d7183b1b 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -84,6 +84,10 @@ struct snd_usb_endpoint { dma_addr_t sync_dma; /* DMA address of syncbuf */ unsigned int pipe; /* the data i/o pipe */ + unsigned int packsize[2]; /* small/large packet sizes in samples */ + unsigned int sample_rem; /* remainder from division fs/pps */ + unsigned int sample_accum; /* sample accumulator */ + unsigned int pps; /* packets per second */ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ int freqshift; /* how much to shift the feedback value to get Q16.16 */ @@ -104,6 +108,7 @@ struct snd_usb_endpoint { int iface, altsetting; int skip_packets; /* quirks for devices to ignore the first n packets in a stream */ + bool is_implicit_feedback; /* This endpoint is used as implicit feedback */ spinlock_t lock; struct list_head list; @@ -132,6 +137,7 @@ struct snd_usb_substream { unsigned int tx_length_quirk:1; /* add length specifier to transfers */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */ + unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */ unsigned int running: 1; /* running status */ @@ -145,6 +151,7 @@ struct snd_usb_substream { struct snd_usb_endpoint *sync_endpoint; unsigned long flags; bool need_setup_ep; /* (re)configure EP at prepare? */ + bool need_setup_fmt; /* (re)configure fmt after resume? */ unsigned int speed; /* USB_SPEED_XXX */ u64 formats; /* format bitmasks (all or'ed) */ diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 72e9bdf76115..b118cf97607f 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -38,39 +38,37 @@ static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, static bool validate_clock_source_v2(void *p, int id) { struct uac_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_source_v3(void *p, int id) { struct uac3_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_selector_v2(void *p, int id) { struct uac_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 7 + cs->bNrInPins; + return cs->bClockID == id; } static bool validate_clock_selector_v3(void *p, int id) { struct uac3_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 11 + cs->bNrInPins; + return cs->bClockID == id; } static bool validate_clock_multiplier_v2(void *p, int id) { struct uac_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } static bool validate_clock_multiplier_v3(void *p, int id) { struct uac3_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; } #define DEFINE_FIND_HELPER(name, obj, validator, type) \ @@ -153,8 +151,71 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i return ret; } +static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + int source_id) +{ + bool ret = false; + int count; + unsigned char data; + struct usb_device *dev = chip->dev; + + if (fmt->protocol == UAC_VERSION_2) { + struct uac_clock_source_descriptor *cs_desc = + snd_usb_find_clock_source(chip->ctrl_intf, source_id); + + if (!cs_desc) + return false; + + /* + * Assume the clock is valid if clock source supports only one + * single sample rate, the terminal is connected directly to it + * (there is no clock selector) and clock type is internal. + * This is to deal with some Denon DJ controllers that always + * reports that clock is invalid. + */ + if (fmt->nr_rates == 1 && + (fmt->clock & 0xff) == cs_desc->bClockID && + (cs_desc->bmAttributes & 0x3) != + UAC_CLOCK_SOURCE_TYPE_EXT) + return true; + } + + /* + * MOTU MicroBook IIc + * Sample rate changes takes more than 2 seconds for this device. Clock + * validity request returns false during that period. + */ + if (chip->usb_id == USB_ID(0x07fd, 0x0004)) { + count = 0; + + while ((!ret) && (count < 50)) { + int err; + + msleep(100); + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, + snd_usb_ctrl_intf(chip) | (source_id << 8), + &data, sizeof(data)); + if (err < 0) { + dev_warn(&dev->dev, + "%s(): cannot get clock validity for id %d\n", + __func__, source_id); + return false; + } + + ret = !!data; + count++; + } + } + + return ret; +} + static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, - int protocol, + struct audioformat *fmt, int source_id) { int err; @@ -162,26 +223,26 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, struct usb_device *dev = chip->dev; u32 bmControls; - if (protocol == UAC_VERSION_3) { + if (fmt->protocol == UAC_VERSION_3) { struct uac3_clock_source_descriptor *cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); if (!cs_desc) - return 0; + return false; bmControls = le32_to_cpu(cs_desc->bmControls); } else { /* UAC_VERSION_1/2 */ struct uac_clock_source_descriptor *cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, source_id); if (!cs_desc) - return 0; + return false; bmControls = cs_desc->bmControls; } /* If a clock source can't tell us whether it's valid, we assume it is */ if (!uac_v2v3_control_is_readable(bmControls, UAC2_CS_CONTROL_CLOCK_VALID)) - return 1; + return true; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, @@ -193,13 +254,17 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, dev_warn(&dev->dev, "%s(): cannot get clock validity for id %d\n", __func__, source_id); - return 0; + return false; } - return !!data; + if (data) + return true; + else + return uac_clock_source_is_valid_quirk(chip, fmt, source_id); } -static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, +static int __uac_clock_find_source(struct snd_usb_audio *chip, + struct audioformat *fmt, int entity_id, unsigned long *visited, bool validate) { struct uac_clock_source_descriptor *source; @@ -219,7 +284,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); if (source) { entity_id = source->bClockID; - if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2, + if (validate && !uac_clock_source_is_valid(chip, fmt, entity_id)) { usb_audio_err(chip, "clock source %d is not valid, cannot use\n", @@ -250,8 +315,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, } cur = ret; - ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], - visited, validate); + ret = __uac_clock_find_source(chip, fmt, + selector->baCSourceID[ret - 1], + visited, validate); if (!validate || ret > 0 || !chip->autoclock) return ret; @@ -262,8 +328,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, if (i == cur) continue; - ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1], - visited, true); + ret = __uac_clock_find_source(chip, fmt, + selector->baCSourceID[i - 1], + visited, true); if (ret < 0) continue; @@ -283,14 +350,16 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, /* FIXME: multipliers only act as pass-thru element for now */ multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); if (multiplier) - return __uac_clock_find_source(chip, multiplier->bCSourceID, - visited, validate); + return __uac_clock_find_source(chip, fmt, + multiplier->bCSourceID, + visited, validate); return -EINVAL; } -static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, - unsigned long *visited, bool validate) +static int __uac3_clock_find_source(struct snd_usb_audio *chip, + struct audioformat *fmt, int entity_id, + unsigned long *visited, bool validate) { struct uac3_clock_source_descriptor *source; struct uac3_clock_selector_descriptor *selector; @@ -309,7 +378,7 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); if (source) { entity_id = source->bClockID; - if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3, + if (validate && !uac_clock_source_is_valid(chip, fmt, entity_id)) { usb_audio_err(chip, "clock source %d is not valid, cannot use\n", @@ -340,7 +409,8 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, } cur = ret; - ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1], + ret = __uac3_clock_find_source(chip, fmt, + selector->baCSourceID[ret - 1], visited, validate); if (!validate || ret > 0 || !chip->autoclock) return ret; @@ -352,8 +422,9 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, if (i == cur) continue; - ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1], - visited, true); + ret = __uac3_clock_find_source(chip, fmt, + selector->baCSourceID[i - 1], + visited, true); if (ret < 0) continue; @@ -374,7 +445,8 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, entity_id); if (multiplier) - return __uac3_clock_find_source(chip, multiplier->bCSourceID, + return __uac3_clock_find_source(chip, fmt, + multiplier->bCSourceID, visited, validate); return -EINVAL; @@ -391,18 +463,18 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, * * Returns the clock source UnitID (>=0) on success, or an error. */ -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, - int entity_id, bool validate) +int snd_usb_clock_find_source(struct snd_usb_audio *chip, + struct audioformat *fmt, bool validate) { DECLARE_BITMAP(visited, 256); memset(visited, 0, sizeof(visited)); - switch (protocol) { + switch (fmt->protocol) { case UAC_VERSION_2: - return __uac_clock_find_source(chip, entity_id, visited, + return __uac_clock_find_source(chip, fmt, fmt->clock, visited, validate); case UAC_VERSION_3: - return __uac3_clock_find_source(chip, entity_id, visited, + return __uac3_clock_find_source(chip, fmt, fmt->clock, visited, validate); default: return -EINVAL; @@ -503,8 +575,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, * automatic clock selection if the current clock is not * valid. */ - clock = snd_usb_clock_find_source(chip, fmt->protocol, - fmt->clock, true); + clock = snd_usb_clock_find_source(chip, fmt, true); if (clock < 0) { /* We did not find a valid clock, but that might be * because the current sample rate does not match an @@ -512,8 +583,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, * and we will do another validation after setting the * rate. */ - clock = snd_usb_clock_find_source(chip, fmt->protocol, - fmt->clock, false); + clock = snd_usb_clock_find_source(chip, fmt, false); if (clock < 0) return clock; } @@ -579,7 +649,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, validation: /* validate clock after rate change */ - if (!uac_clock_source_is_valid(chip, fmt->protocol, clock)) + if (!uac_clock_source_is_valid(chip, fmt, clock)) return -ENXIO; return 0; } diff --git a/sound/usb/clock.h b/sound/usb/clock.h index 076e31b79ee0..68df0fbe09d0 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -6,7 +6,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt, int rate); -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, - int entity_id, bool validate); +int snd_usb_clock_find_source(struct snd_usb_audio *chip, + struct audioformat *fmt, bool validate); #endif /* __USBAUDIO_CLOCK_H */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index a2ab8e8d3a93..88760268fb55 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -124,12 +124,12 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep) /* * For streaming based on information derived from sync endpoints, - * prepare_outbound_urb_sizes() will call next_packet_size() to + * prepare_outbound_urb_sizes() will call slave_next_packet_size() to * determine the number of samples to be sent in the next packet. * - * For implicit feedback, next_packet_size() is unused. + * For implicit feedback, slave_next_packet_size() is unused. */ -int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) +int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep) { unsigned long flags; int ret; @@ -146,6 +146,29 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) return ret; } +/* + * For adaptive and synchronous endpoints, prepare_outbound_urb_sizes() + * will call next_packet_size() to determine the number of samples to be + * sent in the next packet. + */ +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) +{ + int ret; + + if (ep->fill_max) + return ep->maxframesize; + + ep->sample_accum += ep->sample_rem; + if (ep->sample_accum >= ep->pps) { + ep->sample_accum -= ep->pps; + ret = ep->packsize[1]; + } else { + ret = ep->packsize[0]; + } + + return ret; +} + static void retire_outbound_urb(struct snd_usb_endpoint *ep, struct snd_urb_ctx *urb_ctx) { @@ -190,6 +213,8 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep, if (ctx->packet_size[i]) counts = ctx->packet_size[i]; + else if (ep->sync_master) + counts = snd_usb_endpoint_slave_next_packet_size(ep); else counts = snd_usb_endpoint_next_packet_size(ep); @@ -321,17 +346,17 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) ep->next_packet_read_pos %= MAX_URBS; /* take URB out of FIFO */ - if (!list_empty(&ep->ready_playback_urbs)) + if (!list_empty(&ep->ready_playback_urbs)) { ctx = list_first_entry(&ep->ready_playback_urbs, struct snd_urb_ctx, ready_list); + list_del_init(&ctx->ready_list); + } } spin_unlock_irqrestore(&ep->lock, flags); if (ctx == NULL) return; - list_del_init(&ctx->ready_list); - /* copy over the length information */ for (i = 0; i < packet->packets; i++) ctx->packet_size[i] = packet->packet_size[i]; @@ -388,6 +413,9 @@ static void snd_complete_urb(struct urb *urb) } prepare_outbound_urb(ep, ctx); + /* can be stopped during prepare callback */ + if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) + goto exit_clear; } else { retire_inbound_urb(ep, ctx); /* can be stopped during retire callback */ @@ -494,6 +522,8 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, list_add_tail(&ep->list, &chip->ep_list); + ep->is_implicit_feedback = 0; + __exit_unlock: mutex_unlock(&chip->mutex); @@ -594,6 +624,178 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) } /* + * Check data endpoint for format differences + */ +static bool check_ep_params(struct snd_usb_endpoint *ep, + snd_pcm_format_t pcm_format, + unsigned int channels, + unsigned int period_bytes, + unsigned int frames_per_period, + unsigned int periods_per_buffer, + struct audioformat *fmt, + struct snd_usb_endpoint *sync_ep) +{ + unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; + unsigned int max_packs_per_period, urbs_per_period, urb_packs; + unsigned int max_urbs; + int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; + int tx_length_quirk = (ep->chip->tx_length_quirk && + usb_pipeout(ep->pipe)); + bool ret = 1; + + if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { + /* + * When operating in DSD DOP mode, the size of a sample frame + * in hardware differs from the actual physical format width + * because we need to make room for the DOP markers. + */ + frame_bits += channels << 3; + } + + ret = ret && (ep->datainterval == fmt->datainterval); + ret = ret && (ep->stride == frame_bits >> 3); + + switch (pcm_format) { + case SNDRV_PCM_FORMAT_U8: + ret = ret && (ep->silence_value == 0x80); + break; + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + ret = ret && (ep->silence_value == 0x69); + break; + default: + ret = ret && (ep->silence_value == 0); + } + + /* assume max. frequency is 50% higher than nominal */ + ret = ret && (ep->freqmax == ep->freqn + (ep->freqn >> 1)); + /* Round up freqmax to nearest integer in order to calculate maximum + * packet size, which must represent a whole number of frames. + * This is accomplished by adding 0x0.ffff before converting the + * Q16.16 format into integer. + * In order to accurately calculate the maximum packet size when + * the data interval is more than 1 (i.e. ep->datainterval > 0), + * multiply by the data interval prior to rounding. For instance, + * a freqmax of 41 kHz will result in a max packet size of 6 (5.125) + * frames with a data interval of 1, but 11 (10.25) frames with a + * data interval of 2. + * (ep->freqmax << ep->datainterval overflows at 8.192 MHz for the + * maximum datainterval value of 3, at USB full speed, higher for + * USB high speed, noting that ep->freqmax is in units of + * frames per packet in Q16.16 format.) + */ + maxsize = (((ep->freqmax << ep->datainterval) + 0xffff) >> 16) * + (frame_bits >> 3); + if (tx_length_quirk) + maxsize += sizeof(__le32); /* Space for length descriptor */ + /* but wMaxPacketSize might reduce this */ + if (ep->maxpacksize && ep->maxpacksize < maxsize) { + /* whatever fits into a max. size packet */ + unsigned int data_maxsize = maxsize = ep->maxpacksize; + + if (tx_length_quirk) + /* Need to remove the length descriptor to calc freq */ + data_maxsize -= sizeof(__le32); + ret = ret && (ep->freqmax == (data_maxsize / (frame_bits >> 3)) + << (16 - ep->datainterval)); + } + + if (ep->fill_max) + ret = ret && (ep->curpacksize == ep->maxpacksize); + else + ret = ret && (ep->curpacksize == maxsize); + + if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) { + packs_per_ms = 8 >> ep->datainterval; + max_packs_per_urb = MAX_PACKS_HS; + } else { + packs_per_ms = 1; + max_packs_per_urb = MAX_PACKS; + } + if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) + max_packs_per_urb = min(max_packs_per_urb, + 1U << sync_ep->syncinterval); + max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); + + /* + * Capture endpoints need to use small URBs because there's no way + * to tell in advance where the next period will end, and we don't + * want the next URB to complete much after the period ends. + * + * Playback endpoints with implicit sync much use the same parameters + * as their corresponding capture endpoint. + */ + if (usb_pipein(ep->pipe) || + snd_usb_endpoint_implicit_feedback_sink(ep)) { + + urb_packs = packs_per_ms; + /* + * Wireless devices can poll at a max rate of once per 4ms. + * For dataintervals less than 5, increase the packet count to + * allow the host controller to use bursting to fill in the + * gaps. + */ + if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { + int interval = ep->datainterval; + + while (interval < 5) { + urb_packs <<= 1; + ++interval; + } + } + /* make capture URBs <= 1 ms and smaller than a period */ + urb_packs = min(max_packs_per_urb, urb_packs); + while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) + urb_packs >>= 1; + ret = ret && (ep->nurbs == MAX_URBS); + + /* + * Playback endpoints without implicit sync are adjusted so that + * a period fits as evenly as possible in the smallest number of + * URBs. The total number of URBs is adjusted to the size of the + * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits. + */ + } else { + /* determine how small a packet can be */ + minsize = (ep->freqn >> (16 - ep->datainterval)) * + (frame_bits >> 3); + /* with sync from device, assume it can be 12% lower */ + if (sync_ep) + minsize -= minsize >> 3; + minsize = max(minsize, 1u); + + /* how many packets will contain an entire ALSA period? */ + max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize); + + /* how many URBs will contain a period? */ + urbs_per_period = DIV_ROUND_UP(max_packs_per_period, + max_packs_per_urb); + /* how many packets are needed in each URB? */ + urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period); + + /* limit the number of frames in a single URB */ + ret = ret && (ep->max_urb_frames == + DIV_ROUND_UP(frames_per_period, urbs_per_period)); + + /* try to use enough URBs to contain an entire ALSA buffer */ + max_urbs = min((unsigned) MAX_URBS, + MAX_QUEUE * packs_per_ms / urb_packs); + ret = ret && (ep->nurbs == min(max_urbs, + urbs_per_period * periods_per_buffer)); + } + + ret = ret && (ep->datainterval == fmt->datainterval); + ret = ret && (ep->maxpacksize == fmt->maxpacksize); + ret = ret && + (ep->fill_max == !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)); + + return ret; +} + +/* * configure a data endpoint */ static int data_ep_set_params(struct snd_usb_endpoint *ep, @@ -858,10 +1060,23 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, int err; if (ep->use_count != 0) { - usb_audio_warn(ep->chip, - "Unable to change format on ep #%x: already in use\n", - ep->ep_num); - return -EBUSY; + bool check = ep->is_implicit_feedback && + check_ep_params(ep, pcm_format, + channels, period_bytes, + period_frames, buffer_periods, + fmt, sync_ep); + + if (!check) { + usb_audio_warn(ep->chip, + "Unable to change format on ep #%x: already in use\n", + ep->ep_num); + return -EBUSY; + } + + usb_audio_dbg(ep->chip, + "Ep #%x already in use as implicit feedback but format not changed\n", + ep->ep_num); + return 0; } /* release old buffers, if any */ @@ -871,10 +1086,17 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, ep->maxpacksize = fmt->maxpacksize; ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); - if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) + if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) { ep->freqn = get_usb_full_speed_rate(rate); - else + ep->pps = 1000 >> ep->datainterval; + } else { ep->freqn = get_usb_high_speed_rate(rate); + ep->pps = 8000 >> ep->datainterval; + } + + ep->sample_rem = rate % ep->pps; + ep->packsize[0] = rate / ep->pps; + ep->packsize[1] = (rate + (ep->pps - 1)) / ep->pps; /* calculate the frequency in 16.16 format */ ep->freqm = ep->freqn; @@ -933,6 +1155,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) ep->active_mask = 0; ep->unlink_mask = 0; ep->phase = 0; + ep->sample_accum = 0; snd_usb_endpoint_start_quirk(ep); diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 63a39d4fa8d8..d23fa0a8c11b 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -28,6 +28,7 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); void snd_usb_endpoint_free(struct snd_usb_endpoint *ep); int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep); int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, diff --git a/sound/usb/format.c b/sound/usb/format.c index c02b51a82775..f4f0cf3deaf0 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -285,6 +285,36 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, return nr_rates; } +/* Line6 Helix series don't support the UAC2_CS_RANGE usb function + * call. Return a static table of known clock rates. + */ +static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip, + struct audioformat *fp) +{ + switch (chip->usb_id) { + case USB_ID(0x0E41, 0x4241): /* Line6 Helix */ + case USB_ID(0x0E41, 0x4242): /* Line6 Helix Rack */ + case USB_ID(0x0E41, 0x4244): /* Line6 Helix LT */ + case USB_ID(0x0E41, 0x4246): /* Line6 HX-Stomp */ + case USB_ID(0x0E41, 0x4248): /* Line6 Helix >= fw 2.82 */ + case USB_ID(0x0E41, 0x4249): /* Line6 Helix Rack >= fw 2.82 */ + case USB_ID(0x0E41, 0x424a): /* Line6 Helix LT >= fw 2.82 */ + /* supported rates: 48Khz */ + kfree(fp->rate_table); + fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL); + if (!fp->rate_table) + return -ENOMEM; + fp->nr_rates = 1; + fp->rate_min = 48000; + fp->rate_max = 48000; + fp->rates = SNDRV_PCM_RATE_48000; + fp->rate_table[0] = 48000; + return 0; + } + + return -ENODEV; +} + /* * parse the format descriptor and stores the possible sample rates * on the audioformat table (audio class v2 and v3). @@ -294,9 +324,8 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, { struct usb_device *dev = chip->dev; unsigned char tmp[2], *data; - int nr_triplets, data_size, ret = 0; - int clock = snd_usb_clock_find_source(chip, fp->protocol, - fp->clock, false); + int nr_triplets, data_size, ret = 0, ret_l6; + int clock = snd_usb_clock_find_source(chip, fp, false); if (clock < 0) { dev_err(&dev->dev, @@ -313,9 +342,22 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, tmp, sizeof(tmp)); if (ret < 0) { - dev_err(&dev->dev, - "%s(): unable to retrieve number of sample rates (clock %d)\n", + /* line6 helix devices don't support UAC2_CS_CONTROL_SAM_FREQ call */ + ret_l6 = line6_parse_audio_format_rates_quirk(chip, fp); + if (ret_l6 == -ENODEV) { + /* no line6 device found continue showing the error */ + dev_err(&dev->dev, + "%s(): unable to retrieve number of sample rates (clock %d)\n", + __func__, clock); + goto err; + } + if (ret_l6 == 0) { + dev_info(&dev->dev, + "%s(): unable to retrieve number of sample rates: set it to a predefined value (clock %d).\n", __func__, clock); + return 0; + } + ret = ret_l6; goto err; } diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 6afb70156ec4..5e8a18b4e7b9 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -31,4 +31,8 @@ static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; } +/* in validate.c */ +bool snd_usb_validate_audio_desc(void *p, int protocol); +bool snd_usb_validate_midi_desc(void *p); + #endif /* __USBAUDIO_HELPER_H */ diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 82abef3fe90d..4b6e99e055dc 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -287,6 +287,8 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) urb->interval = LINE6_ISO_INTERVAL; urb->error_count = 0; urb->complete = audio_in_callback; + if (usb_urb_ep_type_check(urb)) + return -EINVAL; } return 0; diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index e63a2451c88f..9eac35587f9d 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -316,7 +316,7 @@ static void line6_data_received(struct urb *urb) line6_midibuf_read(mb, line6->buffer_message, LINE6_MIDI_MESSAGE_MAXLEN); - if (done == 0) + if (done <= 0) break; line6->message_length = done; @@ -831,7 +831,7 @@ void line6_disconnect(struct usb_interface *interface) if (WARN_ON(usbdev != line6->usbdev)) return; - cancel_delayed_work(&line6->startup_work); + cancel_delayed_work_sync(&line6->startup_work); if (line6->urb_listen != NULL) line6_stop_listen(line6); diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c index 8d6eefa0d936..6a70463f82c4 100644 --- a/sound/usb/line6/midibuf.c +++ b/sound/usb/line6/midibuf.c @@ -159,7 +159,7 @@ int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, int midi_length_prev = midibuf_message_length(this->command_prev); - if (midi_length_prev > 0) { + if (midi_length_prev > 1) { midi_length = midi_length_prev - 1; repeat = 1; } else diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 2e8ead3f9bc2..797ced329b79 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -432,6 +432,8 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) urb->interval = LINE6_ISO_INTERVAL; urb->error_count = 0; urb->complete = audio_out_callback; + if (usb_urb_ep_type_check(urb)) + return -EINVAL; } return 0; diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 53b53a9a4c6f..db2395a95e3f 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -31,8 +31,7 @@ enum { enum { LINE6_PODHD300, LINE6_PODHD400, - LINE6_PODHD500_0, - LINE6_PODHD500_1, + LINE6_PODHD500, LINE6_PODX3, LINE6_PODX3LIVE, LINE6_PODHD500X, @@ -374,8 +373,7 @@ static const struct usb_device_id podhd_id_table[] = { /* TODO: no need to alloc data interfaces when only audio is used */ { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, - { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, - { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, + { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 }, { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 }, { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE }, { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X }, @@ -408,23 +406,13 @@ static const struct line6_properties podhd_properties_table[] = { .ep_audio_r = 0x82, .ep_audio_w = 0x01, }, - [LINE6_PODHD500_0] = { + [LINE6_PODHD500] = { .id = "PODHD500", .name = "POD HD500", - .capabilities = LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 0, - .ep_ctrl_r = 0x81, - .ep_ctrl_w = 0x01, - .ep_audio_r = 0x86, - .ep_audio_w = 0x02, - }, - [LINE6_PODHD500_1] = { - .id = "PODHD500", - .name = "POD HD500", - .capabilities = LINE6_CAP_PCM + .capabilities = LINE6_CAP_PCM | LINE6_CAP_CONTROL | LINE6_CAP_HWMON, .altsetting = 1, + .ctrl_if = 1, .ep_ctrl_r = 0x81, .ep_ctrl_w = 0x01, .ep_audio_r = 0x86, diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b737f0ec77d0..0cb4142b05f6 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1499,6 +1499,8 @@ void snd_usbmidi_disconnect(struct list_head *p) spin_unlock_irq(&umidi->disc_lock); up_write(&umidi->disc_rwsem); + del_timer_sync(&umidi->error_timer); + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; if (ep->out) @@ -1525,7 +1527,6 @@ void snd_usbmidi_disconnect(struct list_head *p) ep->in = NULL; } } - del_timer_sync(&umidi->error_timer); } EXPORT_SYMBOL(snd_usbmidi_disconnect); @@ -2282,16 +2283,22 @@ void snd_usbmidi_input_stop(struct list_head *p) } EXPORT_SYMBOL(snd_usbmidi_input_stop); -static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint *ep) +static void snd_usbmidi_input_start_ep(struct snd_usb_midi *umidi, + struct snd_usb_midi_in_endpoint *ep) { unsigned int i; + unsigned long flags; if (!ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb *urb = ep->urbs[i]; - urb->dev = ep->umidi->dev; - snd_usbmidi_submit_urb(urb, GFP_KERNEL); + spin_lock_irqsave(&umidi->disc_lock, flags); + if (!atomic_read(&urb->use_count)) { + urb->dev = ep->umidi->dev; + snd_usbmidi_submit_urb(urb, GFP_ATOMIC); + } + spin_unlock_irqrestore(&umidi->disc_lock, flags); } } @@ -2307,7 +2314,7 @@ void snd_usbmidi_input_start(struct list_head *p) if (umidi->input_running || !umidi->opened[1]) return; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) - snd_usbmidi_input_start_ep(umidi->endpoints[i].in); + snd_usbmidi_input_start_ep(umidi, umidi->endpoints[i].in); umidi->input_running = 1; } EXPORT_SYMBOL(snd_usbmidi_input_start); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index eceab19766db..ff8d29bf601f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -576,8 +576,9 @@ static int check_matrix_bitmap(unsigned char *bmap, * if failed, give up and free the control instance. */ -int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, - struct snd_kcontrol *kctl) +int snd_usb_mixer_add_list(struct usb_mixer_elem_list *list, + struct snd_kcontrol *kctl, + bool is_std_info) { struct usb_mixer_interface *mixer = list->mixer; int err; @@ -591,6 +592,7 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, return err; } list->kctl = kctl; + list->is_std_info = is_std_info; list->next_id_elem = mixer->id_elems[list->id]; mixer->id_elems[list->id] = list; return 0; @@ -740,13 +742,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, { int mu_channels; - if (desc->bLength < sizeof(*desc)) - return -EINVAL; - if (!desc->bNrInPins) - return -EINVAL; - if (desc->bLength < sizeof(*desc) + desc->bNrInPins) - return -EINVAL; - switch (state->mixer->protocol) { case UAC_VERSION_1: case UAC_VERSION_2: @@ -765,222 +760,250 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state, } /* - * parse the source unit recursively until it reaches to a terminal - * or a branched unit. + * Parse Input Terminal Unit */ static int __check_input_term(struct mixer_build *state, int id, - struct usb_audio_term *term) + struct usb_audio_term *term); + +static int parse_term_uac1_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) { - int protocol = state->mixer->protocol; + struct uac_input_terminal_descriptor *d = p1; + + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le16_to_cpu(d->wChannelConfig); + term->name = d->iTerminal; + return 0; +} + +static int parse_term_uac2_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac2_input_terminal_descriptor *d = p1; int err; - void *p1; - unsigned char *hdr; - memset(term, 0, sizeof(*term)); - for (;;) { - /* a loop in the terminal chain? */ - if (test_and_set_bit(id, state->termbitmap)) - return -EINVAL; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err; - p1 = find_audio_control_unit(state, id); - if (!p1) - break; + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le32_to_cpu(d->bmChannelConfig); + term->name = d->iTerminal; + return 0; +} - hdr = p1; - term->id = id; +static int parse_term_uac3_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_input_terminal_descriptor *d = p1; + int err; - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: - if (protocol == UAC_VERSION_1) { - struct uac_input_terminal_descriptor *d = p1; - - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le16_to_cpu(d->wChannelConfig); - term->name = d->iTerminal; - } else { /* UAC_VERSION_2 */ - struct uac2_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err; - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le32_to_cpu(d->bmChannelConfig); - term->name = d->iTerminal; - } - return 0; - case UAC_FEATURE_UNIT: { - /* the header is the same for v1 and v2 */ - struct uac_feature_unit_descriptor *d = p1; + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); - id = d->bSourceID; - break; /* continue to parse */ - } - case UAC_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; - - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ - term->channels = uac_mixer_unit_bNrChannels(d); - term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); - term->name = uac_mixer_unit_iMixer(d); - return 0; - } - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = uac_selector_unit_iSelector(d); - return 0; - } - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT */ - if (protocol == UAC_VERSION_1) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - else /* UAC_VERSION_2 */ - term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 */ - if (protocol == UAC_VERSION_1 && !term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ - else if (protocol == UAC_VERSION_2 && !term->type) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC2_EXTENSION_UNIT_V2: { - struct uac_processing_unit_descriptor *d = p1; - - if (protocol == UAC_VERSION_2 && - hdr[2] == UAC2_EFFECT_UNIT) { - /* UAC2/UAC1 unit IDs overlap here in an - * uncompatible way. Ignore this unit for now. - */ - return 0; - } + err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); + if (err < 0) + return err; + term->channels = err; - if (d->bNrInPins) { - id = d->baSourceID[0]; - break; /* continue to parse */ - } - if (!term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ + /* REVISIT: UAC3 IT doesn't have channels cfg */ + term->chconfig = 0; - term->channels = uac_processing_unit_bNrChannels(d); - term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); - term->name = uac_processing_unit_iProcessing(d, protocol); - return 0; - } - case UAC2_CLOCK_SOURCE: { - struct uac_clock_source_descriptor *d = p1; + term->name = le16_to_cpu(d->wTerminalDescrStr); + return 0; +} - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = d->iClockSource; - return 0; - } - default: - return -ENODEV; - } - } else { /* UAC_VERSION_3 */ - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: { - struct uac3_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; +static int parse_term_mixer_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_mixer_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err; - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); + err = uac_mixer_unit_get_channels(state, d); + if (err <= 0) + return err; - err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); - if (err < 0) - return err; - term->channels = err; + term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + term->channels = err; + if (protocol != UAC_VERSION_3) { + term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); + term->name = uac_mixer_unit_iMixer(d); + } + return 0; +} - /* REVISIT: UAC3 IT doesn't have channels cfg */ - term->chconfig = 0; +static int parse_term_selector_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_selector_unit_descriptor *d = p1; + int err; - term->name = le16_to_cpu(d->wTerminalDescrStr); - return 0; - } - case UAC3_FEATURE_UNIT: { - struct uac3_feature_unit_descriptor *d = p1; + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ + term->id = id; + if (state->mixer->protocol != UAC_VERSION_3) + term->name = uac_selector_unit_iSelector(d); + return 0; +} - id = d->bSourceID; - break; /* continue to parse */ - } - case UAC3_CLOCK_SOURCE: { - struct uac3_clock_source_descriptor *d = p1; +static int parse_term_proc_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id, int vtype) +{ + struct uac_processing_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err; - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = le16_to_cpu(d->wClockSourceStr); - return 0; - } - case UAC3_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; + if (d->bNrInPins) { + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + } - err = uac_mixer_unit_get_channels(state, d); - if (err <= 0) - return err; + term->type = vtype << 16; /* virtual type */ + term->id = id; - term->channels = err; - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + if (protocol == UAC_VERSION_3) + return 0; - return 0; - } - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ + if (!term->channels) { + term->channels = uac_processing_unit_bNrChannels(d); + term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); + } + term->name = uac_processing_unit_iProcessing(d, protocol); + return 0; +} - return 0; - } - case UAC3_PROCESSING_UNIT: { - struct uac_processing_unit_descriptor *d = p1; +static int parse_term_effect_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ + term->id = id; + return 0; +} + +static int parse_term_uac2_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_clock_source_descriptor *d = p1; - if (!d->bNrInPins) - return -EINVAL; + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = d->iClockSource; + return 0; +} - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; +static int parse_term_uac3_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_clock_source_descriptor *d = p1; - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = le16_to_cpu(d->wClockSourceStr); + return 0; +} - return 0; - } - default: - return -ENODEV; - } +#define PTYPE(a, b) ((a) << 8 | (b)) + +/* + * parse the source unit recursively until it reaches to a terminal + * or a branched unit. + */ +static int __check_input_term(struct mixer_build *state, int id, + struct usb_audio_term *term) +{ + int protocol = state->mixer->protocol; + void *p1; + unsigned char *hdr; + + for (;;) { + /* a loop in the terminal chain? */ + if (test_and_set_bit(id, state->termbitmap)) + return -EINVAL; + + p1 = find_audio_control_unit(state, id); + if (!p1) + break; + if (!snd_usb_validate_audio_desc(p1, protocol)) + break; /* bad descriptor */ + + hdr = p1; + term->id = id; + + switch (PTYPE(protocol, hdr[2])) { + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): { + /* the header is the same for all versions */ + struct uac_feature_unit_descriptor *d = p1; + + id = d->bSourceID; + break; /* continue to parse */ + } + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + return parse_term_uac1_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + return parse_term_uac2_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_term_uac3_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_term_mixer_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_term_selector_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_PROCESSING_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return parse_term_effect_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_EXTENSION_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + return parse_term_uac2_clock_source(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_term_uac3_clock_source(state, term, p1, id); + default: + return -ENODEV; } } return -ENODEV; @@ -1024,10 +1047,15 @@ static struct usb_feature_control_info audio_feature_info[] = { { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, }; +static void usb_mixer_elem_info_free(struct usb_mixer_elem_info *cval) +{ + kfree(cval); +} + /* private_free callback */ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) { - kfree(kctl->private_data); + usb_mixer_elem_info_free(kctl->private_data); kctl->private_data = NULL; } @@ -1145,6 +1173,14 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 384; } break; + case USB_ID(0x0495, 0x3042): /* ESS Technology Asus USB DAC */ + if ((strstr(kctl->id.name, "Playback Volume") != NULL) || + strstr(kctl->id.name, "Capture Volume") != NULL) { + cval->min >>= 8; + cval->max = 0; + cval->res = 1; + } + break; } } @@ -1211,7 +1247,8 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, if (cval->min + cval->res < cval->max) { int last_valid_res = cval->res; int saved, test, check; - get_cur_mix_raw(cval, minchn, &saved); + if (get_cur_mix_raw(cval, minchn, &saved) < 0) + goto no_res_check; for (;;) { test = saved; if (test < cval->max) @@ -1231,6 +1268,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, snd_usb_set_cur_mix_value(cval, minchn, 0, saved); } +no_res_check: cval->initialized = 1; } @@ -1418,7 +1456,7 @@ error: usb_audio_err(chip, "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", UAC_GET_CUR, validx, idx, cval->val_type); - return ret; + return filter_error(cval, ret); } ucontrol->value.integer.value[0] = val; @@ -1550,7 +1588,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, ctl_info = get_feature_control_info(control); if (!ctl_info) { - kfree(cval); + usb_mixer_elem_info_free(cval); return; } if (mixer->protocol == UAC_VERSION_1) @@ -1583,7 +1621,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -1722,10 +1760,16 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer, /* Build a mixer control for a UAC connector control (jack-detect) */ static void build_connector_control(struct usb_mixer_interface *mixer, + const struct usbmix_name_map *imap, struct usb_audio_term *term, bool is_input) { struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; + const struct usbmix_name_map *map; + + map = find_map(imap, term->id, 0); + if (check_ignored_ctl(map)) + return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (!cval) @@ -1753,11 +1797,15 @@ static void build_connector_control(struct usb_mixer_interface *mixer, kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } - get_connector_control_name(mixer, term, is_input, kctl->id.name, - sizeof(kctl->id.name)); + + if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) + strlcat(kctl->id.name, " Jack", sizeof(kctl->id.name)); + else + get_connector_control_name(mixer, term, is_input, kctl->id.name, + sizeof(kctl->id.name)); kctl->private_free = snd_usb_mixer_elem_free; snd_usb_mixer_add_control(&cval->head, kctl); } @@ -1774,13 +1822,6 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, if (state->mixer->protocol != UAC_VERSION_2) return -EINVAL; - if (hdr->bLength != sizeof(*hdr)) { - usb_audio_dbg(state->chip, - "Bogus clock source descriptor length of %d, ignoring.\n", - hdr->bLength); - return 0; - } - /* * The only property of this unit we are interested in is the * clock source validity. If that isn't readable, just bail out. @@ -1806,7 +1847,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval); if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; } @@ -1839,62 +1880,20 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, __u8 *bmaControls; if (state->mixer->protocol == UAC_VERSION_1) { - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = hdr->bControlSize; - if (!csize) { - usb_audio_dbg(state->chip, - "unit %u: invalid bControlSize == 0\n", - unitid); - return -EINVAL; - } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_feature_unit_descriptor *ftr = _ftr; - if (hdr->bLength < 6) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 6 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else { /* UAC_VERSION_3 */ struct uac3_feature_unit_descriptor *ftr = _ftr; - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (ftr->bLength - 7) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } /* parse the source unit */ @@ -2068,7 +2067,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (!kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2094,15 +2093,11 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid, if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_input_terminal_descriptor *d_v2 = raw_desc; - if (d_v2->bLength < sizeof(*d_v2)) - return -EINVAL; control = UAC2_TE_CONNECTOR; term_id = d_v2->bTerminalID; bmctls = le16_to_cpu(d_v2->bmControls); } else if (state->mixer->protocol == UAC_VERSION_3) { struct uac3_input_terminal_descriptor *d_v3 = raw_desc; - if (d_v3->bLength < sizeof(*d_v3)) - return -EINVAL; control = UAC3_TE_INSERTION; term_id = d_v3->bTerminalID; bmctls = le32_to_cpu(d_v3->bmControls); @@ -2113,8 +2108,9 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid, check_input_term(state, term_id, &iterm); /* Check for jack detection. */ - if (uac_v2v3_control_is_readable(bmctls, control)) - build_connector_control(state->mixer, &iterm, true); + if ((iterm.type & 0xff00) != 0x0100 && + uac_v2v3_control_is_readable(bmctls, control)) + build_connector_control(state->mixer, state->map, &iterm, true); return 0; } @@ -2364,18 +2360,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, const char *name = extension_unit ? "Extension Unit" : "Processing Unit"; - if (desc->bLength < 13) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - num_ins = desc->bNrInPins; - if (desc->bLength < 13 + num_ins || - desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - for (i = 0; i < num_ins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -2466,7 +2451,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2604,7 +2589,7 @@ static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl) if (kctl->private_data) { struct usb_mixer_elem_info *cval = kctl->private_data; num_ins = cval->max; - kfree(cval); + usb_mixer_elem_info_free(cval); kctl->private_data = NULL; } if (kctl->private_value) { @@ -2630,13 +2615,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, const struct usbmix_name_map *map; char **namelist; - if (desc->bLength < 5 || !desc->bNrInPins || - desc->bLength < 5 + desc->bNrInPins) { - usb_audio_err(state->chip, - "invalid SELECTOR UNIT descriptor %d\n", unitid); - return -EINVAL; - } - for (i = 0; i < desc->bNrInPins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -2676,10 +2654,10 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, break; } - namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); + namelist = kcalloc(desc->bNrInPins, sizeof(char *), GFP_KERNEL); if (!namelist) { - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_cval; } #define MAX_ITEM_NAME_LEN 64 for (i = 0; i < desc->bNrInPins; i++) { @@ -2687,11 +2665,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, len = 0; namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); if (!namelist[i]) { - while (i--) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_name; } len = check_mapped_selector_name(state, unitid, i, namelist[i], MAX_ITEM_NAME_LEN); @@ -2705,11 +2680,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); if (! kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - for (i = 0; i < desc->bNrInPins; i++) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_name; } kctl->private_value = (unsigned long)namelist; kctl->private_free = usb_mixer_selector_elem_free; @@ -2755,6 +2727,14 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", cval->head.id, kctl->id.name, desc->bNrInPins); return snd_usb_mixer_add_control(&cval->head, kctl); + + error_name: + for (i = 0; i < desc->bNrInPins; i++) + kfree(namelist[i]); + kfree(namelist); + error_cval: + usb_mixer_elem_info_free(cval); + return err; } /* @@ -2775,62 +2755,49 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return -EINVAL; } - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC2_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_processing_unit(state, unitid, p1); - else - return 0; /* FIXME - effect units not implemented yet */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_extension_unit(state, unitid, p1); - else /* UAC_VERSION_2 */ - return parse_audio_processing_unit(state, unitid, p1); - case UAC2_EXTENSION_UNIT_V2: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } - } else { /* UAC_VERSION_3 */ - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC3_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC3_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC3_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC3_EFFECT_UNIT: - return 0; /* FIXME - effect units not implemented yet */ - case UAC3_PROCESSING_UNIT: - return parse_audio_processing_unit(state, unitid, p1); - case UAC3_EXTENSION_UNIT: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } + if (!snd_usb_validate_audio_desc(p1, protocol)) { + usb_audio_dbg(state->chip, "invalid unit %d\n", unitid); + return 0; /* skip invalid unit */ + } + + switch (PTYPE(protocol, p1[2])) { + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_audio_input_terminal(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_audio_mixer_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_clock_source_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_audio_selector_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): + return parse_audio_feature_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_audio_processing_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_audio_extension_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return 0; /* FIXME - effect units not implemented yet */ + default: + usb_audio_err(state->chip, + "unit %u: unexpected type 0x%02x\n", + unitid, p1[2]); + return -EINVAL; } } @@ -2992,6 +2959,9 @@ static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, continue; iface = usb_ifnum_to_if(dev, intf); + if (!iface) + continue; + num = iface->num_altsetting; if (num < 2) @@ -3101,13 +3071,13 @@ static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, memset(&iterm, 0, sizeof(iterm)); iterm.id = UAC3_BADD_IT_ID4; iterm.type = UAC_BIDIR_TERMINAL_HEADSET; - build_connector_control(mixer, &iterm, true); + build_connector_control(mixer, map->map, &iterm, true); /* Output Term - Insertion control */ memset(&oterm, 0, sizeof(oterm)); oterm.id = UAC3_BADD_OT_ID3; oterm.type = UAC_BIDIR_TERMINAL_HEADSET; - build_connector_control(mixer, &oterm, false); + build_connector_control(mixer, map->map, &oterm, false); } return 0; @@ -3136,7 +3106,8 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) if (map->id == state.chip->usb_id) { state.map = map->map; state.selector_map = map->selector_map; - mixer->ignore_ctl_error = map->ignore_ctl_error; + mixer->connector_map = map->connector_map; + mixer->ignore_ctl_error |= map->ignore_ctl_error; break; } } @@ -3145,11 +3116,12 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { + if (!snd_usb_validate_audio_desc(p, mixer->protocol)) + continue; /* skip invalid descriptor */ + if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3161,8 +3133,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } else if (mixer->protocol == UAC_VERSION_2) { struct uac2_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3180,16 +3150,15 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) if (err < 0 && err != -EINVAL) return err; - if (uac_v2v3_control_is_readable(le16_to_cpu(desc->bmControls), + if ((state.oterm.type & 0xff00) != 0x0100 && + uac_v2v3_control_is_readable(le16_to_cpu(desc->bmControls), UAC2_TE_CONNECTOR)) { - build_connector_control(state.mixer, &state.oterm, - false); + build_connector_control(state.mixer, state.map, + &state.oterm, false); } } else { /* UAC_VERSION_3 */ struct uac3_output_terminal_descriptor *desc = p; - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3207,10 +3176,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) if (err < 0 && err != -EINVAL) return err; - if (uac_v2v3_control_is_readable(le32_to_cpu(desc->bmControls), + if ((state.oterm.type & 0xff00) != 0x0100 && + uac_v2v3_control_is_readable(le32_to_cpu(desc->bmControls), UAC3_TE_INSERTION)) { - build_connector_control(state.mixer, &state.oterm, - false); + build_connector_control(state.mixer, state.map, + &state.oterm, false); } } } @@ -3218,13 +3188,38 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) return 0; } +static int delegate_notify(struct usb_mixer_interface *mixer, int unitid, + u8 *control, u8 *channel) +{ + const struct usbmix_connector_map *map = mixer->connector_map; + + if (!map) + return unitid; + + for (; map->id; map++) { + if (map->id == unitid) { + if (control && map->control) + *control = map->control; + if (channel && map->channel) + *channel = map->channel; + return map->delegated_id; + } + } + return unitid; +} + void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) { struct usb_mixer_elem_list *list; + unitid = delegate_notify(mixer, unitid, NULL, NULL); + for_each_mixer_elem(list, mixer, unitid) { - struct usb_mixer_elem_info *info = - mixer_elem_list_to_info(list); + struct usb_mixer_elem_info *info; + + if (!list->is_std_info) + continue; + info = mixer_elem_list_to_info(list); /* invalidate cache, so the value is read from the device */ info->cached = 0; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, @@ -3291,6 +3286,8 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, return; } + unitid = delegate_notify(mixer, unitid, &control, &channel); + for_each_mixer_elem(list, mixer, unitid) count++; @@ -3302,6 +3299,8 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, if (!list->kctl) continue; + if (!list->is_std_info) + continue; info = mixer_elem_list_to_info(list); if (count > 1 && info->control != control) diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 394cd9107507..2d494d1646b6 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -6,6 +6,13 @@ struct media_mixer_ctl; +struct usbmix_connector_map { + u8 id; + u8 delegated_id; + u8 control; + u8 channel; +}; + struct usb_mixer_interface { struct snd_usb_audio *chip; struct usb_host_interface *hostif; @@ -18,6 +25,9 @@ struct usb_mixer_interface { /* the usb audio specification version this interface complies to */ int protocol; + /* optional connector delegation map */ + const struct usbmix_connector_map *connector_map; + /* Sound Blaster remote control stuff */ const struct rc_config *rc_cfg; u32 rc_code; @@ -52,6 +62,7 @@ struct usb_mixer_elem_list { struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */ struct snd_kcontrol *kctl; unsigned int id; + bool is_std_info; usb_mixer_elem_dump_func_t dump; usb_mixer_elem_resume_func_t resume; }; @@ -89,8 +100,12 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set); -int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, - struct snd_kcontrol *kctl); +int snd_usb_mixer_add_list(struct usb_mixer_elem_list *list, + struct snd_kcontrol *kctl, + bool is_std_info); + +#define snd_usb_mixer_add_control(list, kctl) \ + snd_usb_mixer_add_list(list, kctl, true) void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, struct usb_mixer_interface *mixer, diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 73baf398c84a..ac84f0b2b0bc 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -27,6 +27,7 @@ struct usbmix_ctl_map { u32 id; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; + const struct usbmix_connector_map *connector_map; int ignore_ctl_error; }; @@ -349,6 +350,58 @@ static const struct usbmix_name_map dell_alc4020_map[] = { { 0 } }; +/* Some mobos shipped with a dummy HD-audio show the invalid GET_MIN/GET_MAX + * response for Input Gain Pad (id=19, control=12) and the connector status + * for SPDIF terminal (id=18). Skip them. + */ +static const struct usbmix_name_map asus_rog_map[] = { + { 18, NULL }, /* OT, connector control */ + { 19, NULL, 12 }, /* FU, Input Gain Pad */ + {} +}; + +/* TRX40 mobos with Realtek ALC1220-VB */ +static const struct usbmix_name_map trx40_mobo_map[] = { + { 18, NULL }, /* OT, IEC958 - broken response, disabled */ + { 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */ + { 16, "Speaker" }, /* OT */ + { 22, "Speaker Playback" }, /* FU */ + { 7, "Line" }, /* IT */ + { 19, "Line Capture" }, /* FU */ + { 17, "Front Headphone" }, /* OT */ + { 23, "Front Headphone Playback" }, /* FU */ + { 8, "Mic" }, /* IT */ + { 20, "Mic Capture" }, /* FU */ + { 9, "Front Mic" }, /* IT */ + { 21, "Front Mic Capture" }, /* FU */ + { 24, "IEC958 Playback" }, /* FU */ + {} +}; + +static const struct usbmix_connector_map trx40_mobo_connector_map[] = { + { 10, 16 }, /* (Back) Speaker */ + { 11, 17 }, /* Front Headphone */ + { 13, 7 }, /* Line */ + { 14, 8 }, /* Mic */ + { 15, 9 }, /* Front Mic */ + {} +}; + +/* Rear panel + front mic on Gigabyte TRX40 Aorus Master with ALC1220-VB */ +static const struct usbmix_name_map aorus_master_alc1220vb_map[] = { + { 17, NULL }, /* OT, IEC958?, disabled */ + { 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */ + { 16, "Line Out" }, /* OT */ + { 22, "Line Out Playback" }, /* FU */ + { 7, "Line" }, /* IT */ + { 19, "Line Capture" }, /* FU */ + { 8, "Mic" }, /* IT */ + { 20, "Mic Capture" }, /* FU */ + { 9, "Front Mic" }, /* IT */ + { 21, "Front Mic Capture" }, /* FU */ + {} +}; + /* * Control map entries */ @@ -468,6 +521,38 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x05a7, 0x1020), .map = bose_companion5_map, }, + { /* Gigabyte TRX40 Aorus Master (rear panel + front mic) */ + .id = USB_ID(0x0414, 0xa001), + .map = aorus_master_alc1220vb_map, + }, + { /* Gigabyte TRX40 Aorus Pro WiFi */ + .id = USB_ID(0x0414, 0xa002), + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, + }, + { /* ASUS ROG Zenith II */ + .id = USB_ID(0x0b05, 0x1916), + .map = asus_rog_map, + }, + { /* ASUS ROG Strix */ + .id = USB_ID(0x0b05, 0x1917), + .map = asus_rog_map, + }, + { /* MSI TRX40 Creator */ + .id = USB_ID(0x0db0, 0x0d64), + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, + }, + { /* MSI TRX40 */ + .id = USB_ID(0x0db0, 0x543d), + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, + }, + { /* Asrock TRX40 Creator */ + .id = USB_ID(0x26ce, 0x0a01), + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, + }, { 0 } /* terminator */ }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 27dcb3743690..c48104208fed 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -156,7 +156,8 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, return -ENOMEM; } kctl->private_free = snd_usb_mixer_elem_free; - return snd_usb_mixer_add_control(list, kctl); + /* don't use snd_usb_mixer_add_control() here, this is a special list element */ + return snd_usb_mixer_add_list(list, kctl, false); } /* @@ -182,6 +183,7 @@ static const struct rc_config { { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ { USB_ID(0x041e, 0x3237), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ + { USB_ID(0x041e, 0x3263), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; @@ -1507,11 +1509,15 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, /* use known values for that card: interface#1 altsetting#1 */ iface = usb_ifnum_to_if(chip->dev, 1); - if (!iface || iface->num_altsetting < 2) - return -EINVAL; + if (!iface || iface->num_altsetting < 2) { + err = -EINVAL; + goto end; + } alts = &iface->altsetting[1]; - if (get_iface_desc(alts)->bNumEndpoints < 1) - return -EINVAL; + if (get_iface_desc(alts)->bNumEndpoints < 1) { + err = -EINVAL; + goto end; + } ep = get_endpoint(alts, 0)->bEndpointAddress; err = snd_usb_ctl_msg(chip->dev, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index ff5ab24f3bd1..e837ce55f6ad 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -344,10 +344,22 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, ep = 0x81; ifnum = 1; goto add_sync_ep_from_ifnum; - case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II/IIc */ + /* MicroBook IIc */ + if (altsd->bInterfaceClass == USB_CLASS_AUDIO) + return 0; + + /* MicroBook II */ ep = 0x84; ifnum = 0; goto add_sync_ep_from_ifnum; + case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ + case USB_ID(0x31e9, 0x0001): /* Solid State Logic SSL2 */ + case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */ + case USB_ID(0x0d9a, 0x00df): /* RTX6001 */ + ep = 0x81; + ifnum = 2; + goto add_sync_ep_from_ifnum; case USB_ID(0x0582, 0x01d8): /* BOSS Katana */ /* BOSS Katana amplifiers do not need quirks */ return 0; @@ -370,7 +382,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, add_sync_ep_from_ifnum: iface = usb_ifnum_to_if(dev, ifnum); - if (!iface || iface->num_altsetting == 0) + if (!iface || iface->num_altsetting < 2) return -EINVAL; alts = &iface->altsetting[1]; @@ -382,6 +394,8 @@ add_sync_ep: if (!subs->sync_endpoint) return -EINVAL; + subs->sync_endpoint->is_implicit_feedback = 1; + subs->data_endpoint->sync_master = subs->sync_endpoint; return 1; @@ -480,12 +494,15 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, implicit_fb ? SND_USB_ENDPOINT_TYPE_DATA : SND_USB_ENDPOINT_TYPE_SYNC); + if (!subs->sync_endpoint) { if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) return 0; return -EINVAL; } + subs->sync_endpoint->is_implicit_feedback = implicit_fb; + subs->data_endpoint->sync_master = subs->sync_endpoint; return 0; @@ -506,15 +523,15 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) if (WARN_ON(!iface)) return -EINVAL; alts = usb_altnum_to_altsetting(iface, fmt->altsetting); - altsd = get_iface_desc(alts); - if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) + if (WARN_ON(!alts)) return -EINVAL; + altsd = get_iface_desc(alts); - if (fmt == subs->cur_audiofmt) + if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt) return 0; /* close the old interface */ - if (subs->interface >= 0 && subs->interface != fmt->iface) { + if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) { if (!subs->stream->chip->keep_iface) { err = usb_set_interface(subs->dev, subs->interface, 0); if (err < 0) { @@ -528,6 +545,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) subs->altset_idx = 0; } + if (subs->need_setup_fmt) + subs->need_setup_fmt = false; + /* set interface */ if (iface->cur_altsetting != alts) { err = snd_usb_select_mode_quirk(subs, fmt); @@ -1397,6 +1417,12 @@ static void retire_capture_urb(struct snd_usb_substream *subs, // continue; } bytes = urb->iso_frame_desc[i].actual_length; + if (subs->stream_offset_adj > 0) { + unsigned int adj = min(subs->stream_offset_adj, bytes); + cp += adj; + bytes -= adj; + subs->stream_offset_adj -= adj; + } frames = bytes / stride; if (!subs->txfr_quirk) bytes = frames * stride; @@ -1568,6 +1594,8 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, for (i = 0; i < ctx->packets; i++) { if (ctx->packet_size[i]) counts = ctx->packet_size[i]; + else if (ep->sync_master) + counts = snd_usb_endpoint_slave_next_packet_size(ep); else counts = snd_usb_endpoint_next_packet_size(ep); @@ -1727,6 +1755,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea return 0; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs, false); + subs->data_endpoint->retire_data_urb = NULL; subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -1735,6 +1764,13 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea subs->data_endpoint->retire_data_urb = retire_playback_urb; subs->running = 0; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (subs->stream->chip->setup_fmt_after_resume_quirk) { + stop_endpoints(subs, true); + subs->need_setup_fmt = true; + return 0; + } + break; } return -EINVAL; @@ -1767,6 +1803,13 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream subs->data_endpoint->retire_data_urb = retire_capture_urb; subs->running = 1; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (subs->stream->chip->setup_fmt_after_resume_quirk) { + stop_endpoints(subs, true); + subs->need_setup_fmt = true; + return 0; + } + break; } return -EINVAL; diff --git a/sound/usb/power.c b/sound/usb/power.c index bd303a1ba1b7..606a2cb23eab 100644 --- a/sound/usb/power.c +++ b/sound/usb/power.c @@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, struct uac3_power_domain_descriptor *pd_desc = p; int i; + if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3)) + continue; for (i = 0; i < pd_desc->bNrEntities; i++) { if (pd_desc->baEntityID[i] == id) { pd->pd_id = pd_desc->bPowerDomainID; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 9e049f60e80e..f55b605cfeb7 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -25,6 +25,26 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC +/* HP Thunderbolt Dock Audio Headset */ +{ + USB_DEVICE(0x03f0, 0x0269), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "HP", + .product_name = "Thunderbolt Dock Audio Headset", + .profile_name = "HP-Thunderbolt-Dock-Audio-Headset", + .ifnum = QUIRK_NO_INTERFACE + } +}, +/* HP Thunderbolt Dock Audio Module */ +{ + USB_DEVICE(0x03f0, 0x0567), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "HP", + .product_name = "Thunderbolt Dock Audio Module", + .profile_name = "HP-Thunderbolt-Dock-Audio-Module", + .ifnum = QUIRK_NO_INTERFACE + } +}, /* FTDI devices */ { USB_DEVICE(0x0403, 0xb8d8), @@ -2756,90 +2776,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_NOVATION } }, -{ - /* - * Focusrite Scarlett Solo 2nd generation - * Reports that playback should use Synch: Synchronous - * while still providing a feedback endpoint. Synchronous causes - * snapping on some sample rates. - * Force it to use Synch: Asynchronous. - */ - USB_DEVICE(0x1235, 0x8205), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 1, - .type = QUIRK_AUDIO_FIXED_ENDPOINT, - .data = & (const struct audioformat) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 2, - .iface = 1, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .endpoint = 0x01, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .protocol = UAC_VERSION_2, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .rate_min = 44100, - .rate_max = 192000, - .nr_rates = 6, - .rate_table = (unsigned int[]) { - 44100, 48000, 88200, - 96000, 176400, 192000 - }, - .clock = 41 - } - }, - { - .ifnum = 2, - .type = QUIRK_AUDIO_FIXED_ENDPOINT, - .data = & (const struct audioformat) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 2, - .iface = 2, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .endpoint = 0x82, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC | - USB_ENDPOINT_USAGE_IMPLICIT_FB, - .protocol = UAC_VERSION_2, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .rate_min = 44100, - .rate_max = 192000, - .nr_rates = 6, - .rate_table = (unsigned int[]) { - 44100, 48000, 88200, - 96000, 176400, 192000 - }, - .clock = 41 - } - }, - { - .ifnum = 3, - .type = QUIRK_IGNORE_INTERFACE - }, - { - .ifnum = -1 - } - } - } -}, /* Access Music devices */ { @@ -3466,12 +3402,13 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .vendor_name = "Dell", .product_name = "WD19 Dock", .profile_name = "Dell-WD15-Dock", - .ifnum = QUIRK_NO_INTERFACE + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_SETUP_FMT_AFTER_RESUME } }, /* MOTU Microbook II */ { - USB_DEVICE(0x07fd, 0x0004), + USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004), .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { .vendor_name = "MOTU", .product_name = "MicroBookII", @@ -3534,5 +3471,201 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, +{ + /* + * Pioneer DJ DJM-250MK2 + * PCM is 8 channels out @ 48 fixed (endpoints 0x01). + * The output from computer to the mixer is usable. + * + * The input (phono or line to computer) is not working. + * It should be at endpoint 0x82 and probably also 8 channels, + * but it seems that it works only with Pioneer proprietary software. + * Even on officially supported OS, the Audacity was unable to record + * and Mixxx to recognize the control vinyls. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // outputs + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 48000 } + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* + * PIONEER DJ DDJ-RB + * PCM is 4 channels out, 2 dummy channels in @ 44.1 fixed + * The feedback for the output is the dummy input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000e), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = -1 + } + } + } +}, + +#define ALC1220_VB_DESKTOP(vend, prod) { \ + USB_DEVICE(vend, prod), \ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \ + .vendor_name = "Realtek", \ + .product_name = "ALC1220-VB-DT", \ + .profile_name = "Realtek-ALC1220-VB-Desktop", \ + .ifnum = QUIRK_NO_INTERFACE \ + } \ +} +ALC1220_VB_DESKTOP(0x0414, 0xa002), /* Gigabyte TRX40 Aorus Pro WiFi */ +ALC1220_VB_DESKTOP(0x0db0, 0x0d64), /* MSI TRX40 Creator */ +ALC1220_VB_DESKTOP(0x0db0, 0x543d), /* MSI TRX40 */ +ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */ +#undef ALC1220_VB_DESKTOP + +/* Two entries for Gigabyte TRX40 Aorus Master: + * TRX40 Aorus Master has two USB-audio devices, one for the front headphone + * with ESS SABRE9218 DAC chip, while another for the rest I/O (the rear + * panel and the front mic) with Realtek ALC1220-VB. + * Here we provide two distinct names for making UCM profiles easier. + */ +{ + USB_DEVICE(0x0414, 0xa000), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Gigabyte", + .product_name = "Aorus Master Front Headphone", + .profile_name = "Gigabyte-Aorus-Master-Front-Headphone", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + USB_DEVICE(0x0414, 0xa001), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Gigabyte", + .product_name = "Aorus Master Main Audio", + .profile_name = "Gigabyte-Aorus-Master-Main-Audio", + .ifnum = QUIRK_NO_INTERFACE + } +}, + +/* + * 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 pretend to be 96kHz mono as a workaround for stereo being broken + * by that... + * + * They also have an issue with initial stream alignment that causes the + * channels to be swapped and out of phase, which is dealt with in quirks.c. + */ +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x534d, + .idProduct = 0x2109, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "MacroSilicon", + .product_name = "MS2109", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = &(const struct snd_usb_audio_quirk[]) { + { + .ifnum = 2, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + { + .ifnum = 3, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 3, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0, + .endpoint = 0x82, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 48000, + .rate_max = 48000, + } + }, + { + .ifnum = -1 + } + } + } +}, #undef USB_DEVICE_VENDOR_SPEC diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b6f7b13768a1..a756f50d9f07 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -248,6 +248,9 @@ static int create_yamaha_midi_quirk(struct snd_usb_audio *chip, NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV; + if ((injd && !snd_usb_validate_midi_desc(injd)) || + (outjd && !snd_usb_validate_midi_desc(outjd))) + return -ENODEV; if (injd && (injd->bLength < 5 || (injd->bJackType != USB_MS_EMBEDDED && injd->bJackType != USB_MS_EXTERNAL))) @@ -505,6 +508,16 @@ static int create_standard_mixer_quirk(struct snd_usb_audio *chip, return snd_usb_create_mixer(chip, quirk->ifnum, 0); } + +static int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + struct usb_driver *driver, + const struct snd_usb_audio_quirk *quirk) +{ + chip->setup_fmt_after_resume_quirk = 1; + return 1; /* Continue with creating streams and mixer */ +} + /* * audio-interface quirks * @@ -543,6 +556,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [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_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk, }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -1099,6 +1113,31 @@ free_buf: return err; } +static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) +{ + int ret; + + if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) + return -EINVAL; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, 0, NULL, 0, 1000); + + if (ret < 0) + return ret; + + msleep(2000); + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x20, 0, NULL, 0, 1000); + + if (ret < 0) + return ret; + + return 0; +} + /* * Setup quirks */ @@ -1277,7 +1316,28 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */ return snd_usb_axefx3_boot_quirk(dev); case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ - return snd_usb_motu_microbookii_boot_quirk(dev); + /* + * For some reason interface 3 with vendor-spec class is + * detected on MicroBook IIc. + */ + if (get_iface_desc(intf->altsetting)->bInterfaceClass == + USB_CLASS_VENDOR_SPEC && + get_iface_desc(intf->altsetting)->bInterfaceNumber < 3) + return snd_usb_motu_microbookii_boot_quirk(dev); + break; + } + + return 0; +} + +int snd_usb_apply_boot_quirk_once(struct usb_device *dev, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk, + unsigned int id) +{ + switch (id) { + case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ + return snd_usb_motu_m_series_boot_quirk(dev); } return 0; @@ -1372,6 +1432,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */ set_format_emu_quirk(subs, fmt); break; + case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */ + subs->stream_offset_adj = 2; + break; } } @@ -1383,10 +1446,12 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) 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 */ return true; } @@ -1407,6 +1472,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) 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 */ @@ -1538,15 +1604,24 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) msleep(20); - /* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here, - * otherwise requests like get/set frequency return as failed despite - * actually succeeding. + /* Zoom R16/24, Logitech H650e, 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) || chip->usb_id == USB_ID(0x046d, 0x0a46) || - chip->usb_id == USB_ID(0x0b0e, 0x0349)) && + chip->usb_id == USB_ID(0x0b0e, 0x0349) || + chip->usb_id == USB_ID(0x0951, 0x16ad)) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) 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) + usleep_range(5000, 6000); } /* @@ -1563,7 +1638,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, struct usb_interface *iface; /* Playback Designs */ - if (USB_ID_VENDOR(chip->usb_id) == 0x23ba) { + if (USB_ID_VENDOR(chip->usb_id) == 0x23ba && + USB_ID_PRODUCT(chip->usb_id) < 0x0110) { switch (fp->altsetting) { case 1: fp->dsd_dop = true; @@ -1580,9 +1656,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, /* XMOS based USB DACs */ switch (chip->usb_id) { case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */ - case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ - case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */ - case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */ case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */ case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */ if (fp->altsetting == 2) @@ -1591,12 +1664,11 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */ case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */ - case USB_ID(0x16b0, 0x06b2): /* NuPrime DAC-10 */ + case USB_ID(0x16d0, 0x06b2): /* NuPrime DAC-10 */ case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */ case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */ case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */ case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */ - case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */ case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */ case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */ case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ @@ -1651,9 +1723,13 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, * from XMOS/Thesycon */ switch (USB_ID_VENDOR(chip->usb_id)) { - case 0x20b1: /* XMOS based devices */ 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 0x2ab6: /* T+A devices */ case 0x3842: /* EVGA */ case 0xc502: /* HiBy devices */ @@ -1699,5 +1775,62 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, else fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; break; + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook IIc */ + /* + * MaxPacketsOnly attribute is erroneously set in endpoint + * descriptors. As a result this card produces noise with + * all sample rates other than 96 KHz. + */ + fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX; + break; + case USB_ID(0x1235, 0x8202): /* Focusrite Scarlett 2i2 2nd gen */ + case USB_ID(0x1235, 0x8205): /* Focusrite Scarlett Solo 2nd gen */ + /* + * Reports that playback should use Synch: Synchronous + * while still providing a feedback endpoint. + * Synchronous causes snapping on some sample rates. + * Force it to use Synch: Asynchronous. + */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; + fp->ep_attr |= USB_ENDPOINT_SYNC_ASYNC; + } + break; } } + +/* + * registration quirk: + * the registration is skipped if a device matches with the given ID, + * unless the interface reaches to the defined one. This is for delaying + * the registration until the last known interface, so that the card and + * devices appear at the same time. + */ + +struct registration_quirk { + unsigned int usb_id; /* composed via USB_ID() */ + unsigned int interface; /* the interface to trigger register */ +}; + +#define REG_QUIRK_ENTRY(vendor, product, iface) \ + { .usb_id = USB_ID(vendor, product), .interface = (iface) } + +static const struct registration_quirk registration_quirks[] = { + REG_QUIRK_ENTRY(0x0951, 0x16d8, 2), /* Kingston HyperX AMP */ + REG_QUIRK_ENTRY(0x0951, 0x16ed, 2), /* Kingston HyperX Cloud Alpha S */ + REG_QUIRK_ENTRY(0x0951, 0x16ea, 2), /* Kingston HyperX Cloud Flight S */ + { 0 } /* terminator */ +}; + +/* return true if skipping registration */ +bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface) +{ + const struct registration_quirk *q; + + for (q = registration_quirks; q->usb_id; q++) + if (chip->usb_id == q->usb_id) + return iface != q->interface; + + /* Register as normal */ + return false; +} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index a80e0ddd0736..c76cf24a640a 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -20,6 +20,11 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, const struct snd_usb_audio_quirk *quirk, unsigned int usb_id); +int snd_usb_apply_boot_quirk_once(struct usb_device *dev, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk, + unsigned int usb_id); + void snd_usb_set_format_quirk(struct snd_usb_substream *subs, struct audioformat *fmt); @@ -46,4 +51,6 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, struct audioformat *fp, int stream); +bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface); + #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c index e852c7fd6109..3a17c4c53f87 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -89,6 +89,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->tx_length_quirk = as->chip->tx_length_quirk; subs->speed = snd_usb_get_speed(subs->dev); subs->pkt_offset_adj = 0; + subs->stream_offset_adj = 0; snd_usb_set_pcm_ops(as->pcm, stream); @@ -627,16 +628,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, */ static void * snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id, bool uac23) + int terminal_id, int protocol) { struct uac2_input_terminal_descriptor *term = NULL; - size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) : - sizeof(struct uac_input_terminal_descriptor); while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_INPUT_TERMINAL))) { - if (term->bLength < minlen) + if (!snd_usb_validate_audio_desc(term, protocol)) continue; if (term->bTerminalID == terminal_id) return term; @@ -647,7 +646,7 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, static void * snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) + int terminal_id, int protocol) { /* OK to use with both UAC2 and UAC3 */ struct uac2_output_terminal_descriptor *term = NULL; @@ -655,8 +654,9 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_OUTPUT_TERMINAL))) { - if (term->bLength >= sizeof(*term) && - term->bTerminalID == terminal_id) + if (!snd_usb_validate_audio_desc(term, protocol)) + continue; + if (term->bTerminalID == terminal_id) return term; } @@ -731,7 +731,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - false); + protocol); if (iterm) { num_channels = iterm->bNrChannels; chconfig = le16_to_cpu(iterm->wChannelConfig); @@ -767,7 +767,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + protocol); if (input_term) { clock = input_term->bCSourceID; if (!chconfig && (num_channels == input_term->bNrChannels)) @@ -776,7 +776,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, } output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + protocol); if (output_term) { clock = output_term->bCSourceID; goto found_clock; @@ -1002,14 +1003,15 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + UAC_VERSION_3); if (input_term) { clock = input_term->bCSourceID; goto found_clock; } output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + UAC_VERSION_3); if (output_term) { clock = output_term->bCSourceID; goto found_clock; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index feb30f9c1716..55a2119c2411 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -26,14 +26,14 @@ struct snd_usb_audio { struct usb_interface *pm_intf; u32 usb_id; struct mutex mutex; - unsigned int autosuspended:1; + unsigned int system_suspend; atomic_t active; 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 setup_fmt_after_resume_quirk:1; /* setup the format to interface after resume */ int num_interfaces; int num_suspended_intf; int sample_rate_read_error; @@ -98,6 +98,7 @@ enum quirk_type { QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_AUDIO_STANDARD_MIXER, + QUIRK_SETUP_FMT_AFTER_RESUME, QUIRK_TYPE_COUNT }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index d1caa8ed9e68..9985fc139487 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -119,7 +119,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code if (us428->chip_status & USX2Y_STAT_CHIP_INIT) info->chip_ready = 1; - info->version = USX2Y_DRIVER_VERSION; + info->version = USX2Y_DRIVER_VERSION; return 0; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 89fa287678fc..e0bace4d1c40 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -681,6 +681,8 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) us->submitted = 2*NOOF_SETRATE_URBS; for (i = 0; i < NOOF_SETRATE_URBS; ++i) { struct urb *urb = us->urb[i]; + if (!urb) + continue; if (urb->status) { if (!err) err = -ENODEV; diff --git a/sound/usb/validate.c b/sound/usb/validate.c new file mode 100644 index 000000000000..079f1713e6d1 --- /dev/null +++ b/sound/usb/validate.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Validation of USB-audio class descriptors +// + +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> +#include <linux/usb/midi.h> +#include "usbaudio.h" +#include "helper.h" + +struct usb_desc_validator { + unsigned char protocol; + unsigned char type; + bool (*func)(const void *p, const struct usb_desc_validator *v); + size_t size; +}; + +#define UAC_VERSION_ALL (unsigned char)(-1) + +/* UAC1 only */ +static bool validate_uac1_header(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac1_ac_header_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bInCollection; +} + +/* for mixer unit; covering all UACs */ +static bool validate_mixer_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_mixer_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d) || !d->bNrInPins) + return false; + len = sizeof(*d) + d->bNrInPins; + /* We can't determine the bitmap size only from this unit descriptor, + * so just check with the remaining length. + * The actual bitmap is checked at mixer unit parser. + */ + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 2 + 1; /* wChannelConfig, iChannelNames */ + /* bmControls[n*m] */ + len += 1; /* iMixer */ + break; + case UAC_VERSION_2: + len += 4 + 1; /* bmChannelConfig, iChannelNames */ + /* bmMixerControls[n*m] */ + len += 1 + 1; /* bmControls, iMixer */ + break; + case UAC_VERSION_3: + len += 2; /* wClusterDescrID */ + /* bmMixerControls[n*m] */ + break; + } + return d->bLength >= len; +} + +/* both for processing and extension units; covering all UACs */ +static bool validate_processing_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_processing_unit_descriptor *d = p; + const unsigned char *hdr = p; + size_t len, m; + + if (d->bLength < sizeof(*d)) + return false; + len = sizeof(*d) + d->bNrInPins; + if (d->bLength < len) + return false; + switch (v->protocol) { + case UAC_VERSION_1: + default: + /* bNrChannels, wChannelConfig, iChannelNames */ + len += 1 + 2 + 1; + if (d->bLength < len + 1) /* bControlSize */ + return false; + m = hdr[len]; + len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */ + break; + case UAC_VERSION_2: + /* bNrChannels, bmChannelConfig, iChannelNames */ + len += 1 + 4 + 1; + if (v->type == UAC2_PROCESSING_UNIT_V2) + len += 2; /* bmControls -- 2 bytes for PU */ + else + len += 1; /* bmControls -- 1 byte for EU */ + len += 1; /* iProcessing */ + break; + case UAC_VERSION_3: + /* wProcessingDescrStr, bmControls */ + len += 2 + 4; + break; + } + if (d->bLength < len) + return false; + + switch (v->protocol) { + case UAC_VERSION_1: + default: + if (v->type == UAC1_EXTENSION_UNIT) + return true; /* OK */ + switch (le16_to_cpu(d->wProcessType)) { + case UAC_PROCESS_UP_DOWNMIX: + case UAC_PROCESS_DOLBY_PROLOGIC: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_2: + if (v->type == UAC2_EXTENSION_UNIT_V2) + return true; /* OK */ + switch (le16_to_cpu(d->wProcessType)) { + case UAC2_PROCESS_UP_DOWNMIX: + case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */ + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 4; /* bNrModes, daModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_3: + if (v->type == UAC3_EXTENSION_UNIT) { + len += 2; /* wClusterDescrID */ + break; + } + switch (le16_to_cpu(d->wProcessType)) { + case UAC3_PROCESS_UP_DOWNMIX: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */ + break; + case UAC3_PROCESS_MULTI_FUNCTION: + len += 2 + 4; /* wClusterDescrID, bmAlgorighms */ + break; + default: + break; + } + break; + } + if (d->bLength < len) + return false; + + return true; +} + +/* both for selector and clock selector units; covering all UACs */ +static bool validate_selector_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_selector_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d)) + return false; + len = sizeof(*d) + d->bNrInPins; + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 1; /* iSelector */ + break; + case UAC_VERSION_2: + len += 1 + 1; /* bmControls, iSelector */ + break; + case UAC_VERSION_3: + len += 4 + 2; /* bmControls, wSelectorDescrStr */ + break; + } + return d->bLength >= len; +} + +static bool validate_uac1_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d) || !d->bControlSize) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + d->bControlSize + 1; +} + +static bool validate_uac2_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac2_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + 4 + 1; +} + +static bool validate_uac3_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac3_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + wFeatureDescrStr */ + return d->bLength >= sizeof(*d) + 4 + 2; +} + +static bool validate_midi_out_jack(const void *p, + const struct usb_desc_validator *v) +{ + const struct usb_midi_out_jack_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bNrInputPins * 2; +} + +#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) } +#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) } + +static struct usb_desc_validator audio_validators[] = { + /* UAC1 */ + FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header), + FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL, + struct uac_input_terminal_descriptor), + FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL, + struct uac1_output_terminal_descriptor), + FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit), + FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit), + + /* UAC2 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor), + FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL, + struct uac2_input_terminal_descriptor), + FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL, + struct uac2_output_terminal_descriptor), + FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit), + /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit), + FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE, + struct uac_clock_source_descriptor), + FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER, + struct uac_clock_multiplier_descriptor), + /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */ + + /* UAC3 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor), + FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL, + struct uac3_input_terminal_descriptor), + FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL, + struct uac3_output_terminal_descriptor), + /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit), + /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE, + struct uac3_clock_source_descriptor), + FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER, + struct uac3_clock_multiplier_descriptor), + /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */ + /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */ + { } /* terminator */ +}; + +static struct usb_desc_validator midi_validators[] = { + FIXED(UAC_VERSION_ALL, USB_MS_HEADER, + struct usb_ms_header_descriptor), + FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK, + struct usb_midi_in_jack_descriptor), + FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK, + validate_midi_out_jack), + { } /* terminator */ +}; + + +/* Validate the given unit descriptor, return true if it's OK */ +static bool validate_desc(unsigned char *hdr, int protocol, + const struct usb_desc_validator *v) +{ + if (hdr[1] != USB_DT_CS_INTERFACE) + return true; /* don't care */ + + for (; v->type; v++) { + if (v->type == hdr[2] && + (v->protocol == UAC_VERSION_ALL || + v->protocol == protocol)) { + if (v->func) + return v->func(hdr, v); + /* check for the fixed size */ + return hdr[0] >= v->size; + } + } + + return true; /* not matching, skip validation */ +} + +bool snd_usb_validate_audio_desc(void *p, int protocol) +{ + return validate_desc(p, protocol, audio_validators); +} + +bool snd_usb_validate_midi_desc(void *p) +{ + return validate_desc(p, UAC_VERSION_1, midi_validators); +} |