diff options
Diffstat (limited to 'sound/usb/stream.c')
-rw-r--r-- | sound/usb/stream.c | 85 |
1 files changed, 61 insertions, 24 deletions
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index ca76ba5b5c0b..c1ea8844a46f 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -47,7 +47,6 @@ static void free_substream(struct snd_usb_substream *subs) return; /* not initialized */ list_for_each_entry_safe(fp, n, &subs->fmt_list, list) audioformat_free(fp); - kfree(subs->rate_list.list); kfree(subs->str_pd); snd_media_stream_delete(subs); } @@ -90,8 +89,8 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->stream = as; subs->direction = stream; subs->dev = as->chip->dev; - subs->txfr_quirk = as->chip->txfr_quirk; - subs->tx_length_quirk = as->chip->tx_length_quirk; + subs->txfr_quirk = !!(as->chip->quirk_flags & QUIRK_FLAG_ALIGN_TRANSFER); + subs->tx_length_quirk = !!(as->chip->quirk_flags & QUIRK_FLAG_TX_LENGTH); subs->speed = snd_usb_get_speed(subs->dev); subs->pkt_offset_adj = 0; subs->stream_offset_adj = 0; @@ -193,16 +192,16 @@ static int usb_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_usb_substream *subs = info->private_data; struct snd_pcm_chmap_elem *chmap = NULL; - int i; + int i = 0; - memset(ucontrol->value.integer.value, 0, - sizeof(ucontrol->value.integer.value)); if (subs->cur_audiofmt) chmap = subs->cur_audiofmt->chmap; if (chmap) { for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; } + for (; i < subs->channels_max; i++) + ucontrol->value.integer.value[i] = 0; return 0; } @@ -245,8 +244,8 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, SNDRV_CHMAP_FR, /* right front */ SNDRV_CHMAP_FC, /* center front */ SNDRV_CHMAP_LFE, /* LFE */ - SNDRV_CHMAP_SL, /* left surround */ - SNDRV_CHMAP_SR, /* right surround */ + SNDRV_CHMAP_RL, /* left surround */ + SNDRV_CHMAP_RR, /* right surround */ SNDRV_CHMAP_FLC, /* left of center */ SNDRV_CHMAP_FRC, /* right of center */ SNDRV_CHMAP_RC, /* surround */ @@ -301,9 +300,12 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, c = 0; if (bits) { - for (; bits && *maps; maps++, bits >>= 1) + for (; bits && *maps; maps++, bits >>= 1) { if (bits & 1) chmap->map[c++] = *maps; + if (c == chmap->channels) + break; + } } else { /* If we're missing wChannelConfig, then guess something to make sure the channel map is not skipped entirely */ @@ -496,6 +498,10 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, return 0; } } + + if (chip->card->registered) + chip->need_delayed_register = true; + /* look for an empty stream */ list_for_each_entry(as, &chip->pcm_list, list) { if (as->fmt_type != fp->fmt_type) @@ -503,9 +509,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, subs = &as->substream[stream]; if (subs->ep_num) continue; - if (snd_device_get_state(chip->card, as->pcm) != - SNDRV_DEV_BUILD) - chip->need_delayed_register = true; err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) return err; @@ -710,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, struct usb_device *dev = chip->dev; struct uac_format_type_i_continuous_descriptor *fmt; unsigned int num_channels = 0, chconfig = 0; + struct usb_host_interface *ctrl_intf; struct audioformat *fp; int clock = 0; u64 format; + ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + /* get audio formats */ if (protocol == UAC_VERSION_1) { struct uac1_as_header_descriptor *as = @@ -737,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, format = le16_to_cpu(as->wFormatTag); /* remember the format value */ - iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf, as->bTerminalLink, protocol); if (iterm) { @@ -773,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, * lookup the terminal associated to this interface * to extract the clock */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, as->bTerminalLink, protocol); if (input_term) { @@ -783,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, goto found_clock; } - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, as->bTerminalLink, protocol); if (output_term) { @@ -867,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, struct uac3_cluster_header_descriptor *cluster; struct uac3_as_header_descriptor *as = NULL; struct uac3_hc_descriptor_header hc_header; + struct usb_host_interface *ctrl_intf; struct snd_pcm_chmap_elem *chmap; struct snd_usb_power_domain *pd; unsigned char badd_profile; @@ -878,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, int err; badd_profile = chip->badd_profile; + ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { unsigned int maxpacksize = @@ -963,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, cluster_id, - snd_usb_ctrl_intf(chip), + snd_usb_ctrl_intf(ctrl_intf), &hc_header, sizeof(hc_header)); if (err < 0) return ERR_PTR(err); @@ -987,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, cluster_id, - snd_usb_ctrl_intf(chip), + snd_usb_ctrl_intf(ctrl_intf), cluster, wLength); if (err < 0) { kfree(cluster); @@ -1008,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, * lookup the terminal associated to this interface * to extract the clock */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, as->bTerminalLink, UAC_VERSION_3); if (input_term) { @@ -1016,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, goto found_clock; } - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, as->bTerminalLink, UAC_VERSION_3); if (output_term) { @@ -1059,13 +1067,14 @@ found_clock: UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11; pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0; pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0; + pd->ctrl_iface = ctrl_intf; } else { fp->attributes = parse_uac_endpoint_attributes(chip, alts, UAC_VERSION_3, iface_no); - pd = snd_usb_find_power_domain(chip->ctrl_intf, + pd = snd_usb_find_power_domain(ctrl_intf, as->bTerminalLink); /* ok, let's parse further... */ @@ -1093,6 +1102,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int i, altno, err, stream; struct audioformat *fp = NULL; struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; int num, protocol; dev = chip->dev; @@ -1106,7 +1116,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, * Dallas DS4201 workaround: It presents 5 altsettings, but the last * one misses syncpipe, and does not produce any sound. */ - if (chip->usb_id == USB_ID(0x04fa, 0x4201)) + if (chip->usb_id == USB_ID(0x04fa, 0x4201) && num >= 4) num = 4; for (i = 0; i < num; i++) { @@ -1194,6 +1204,8 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, continue; } + snd_usb_audioformat_set_sync_ep(chip, fp); + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); if (protocol == UAC_VERSION_3) err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); @@ -1205,10 +1217,35 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, kfree(pd); return err; } + + /* add endpoints */ + err = snd_usb_add_endpoint(chip, fp->endpoint, + SND_USB_ENDPOINT_TYPE_DATA); + if (err < 0) + return err; + + if (fp->sync_ep) { + err = snd_usb_add_endpoint(chip, fp->sync_ep, + fp->implicit_fb ? + SND_USB_ENDPOINT_TYPE_DATA : + SND_USB_ENDPOINT_TYPE_SYNC); + if (err < 0) + return err; + } + + set_iface_first = false; + if (protocol == UAC_VERSION_1 || + (chip->quirk_flags & QUIRK_FLAG_SET_IFACE_FIRST)) + set_iface_first = true; + /* try to set the interface... */ - usb_set_interface(chip->dev, iface_no, altno); - snd_usb_init_pitch(chip, iface_no, alts, fp); - snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); + usb_set_interface(chip->dev, iface_no, 0); + if (set_iface_first) + usb_set_interface(chip->dev, iface_no, altno); + snd_usb_init_pitch(chip, fp); + snd_usb_init_sample_rate(chip, fp, fp->rate_max); + if (!set_iface_first) + usb_set_interface(chip->dev, iface_no, altno); } return 0; } |