aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/usb/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/stream.c')
-rw-r--r--sound/usb/stream.c85
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;
}