|
@@ -37,6 +37,7 @@
|
|
|
#include "format.h"
|
|
|
#include "clock.h"
|
|
|
#include "stream.h"
|
|
|
+#include "power.h"
|
|
|
|
|
|
/*
|
|
|
* free a substream
|
|
@@ -53,6 +54,7 @@ static void free_substream(struct snd_usb_substream *subs)
|
|
|
kfree(fp);
|
|
|
}
|
|
|
kfree(subs->rate_list.list);
|
|
|
+ kfree(subs->str_pd);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -82,7 +84,8 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
|
|
|
|
|
|
static void snd_usb_init_substream(struct snd_usb_stream *as,
|
|
|
int stream,
|
|
|
- struct audioformat *fp)
|
|
|
+ struct audioformat *fp,
|
|
|
+ struct snd_usb_power_domain *pd)
|
|
|
{
|
|
|
struct snd_usb_substream *subs = &as->substream[stream];
|
|
|
|
|
@@ -107,6 +110,9 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
|
|
|
if (fp->channels > subs->channels_max)
|
|
|
subs->channels_max = fp->channels;
|
|
|
|
|
|
+ if (pd)
|
|
|
+ subs->str_pd = pd;
|
|
|
+
|
|
|
snd_usb_preallocate_buffer(subs);
|
|
|
}
|
|
|
|
|
@@ -468,9 +474,11 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
|
|
|
* fmt_list and will be freed on the chip instance release. do not free
|
|
|
* fp or do remove it from the substream fmt_list to avoid double-free.
|
|
|
*/
|
|
|
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
- int stream,
|
|
|
- struct audioformat *fp)
|
|
|
+static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
+ int stream,
|
|
|
+ struct audioformat *fp,
|
|
|
+ struct snd_usb_power_domain *pd)
|
|
|
+
|
|
|
{
|
|
|
struct snd_usb_stream *as;
|
|
|
struct snd_usb_substream *subs;
|
|
@@ -498,7 +506,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
err = snd_pcm_new_stream(as->pcm, stream, 1);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
- snd_usb_init_substream(as, stream, fp);
|
|
|
+ snd_usb_init_substream(as, stream, fp, pd);
|
|
|
return add_chmap(as->pcm, stream, subs);
|
|
|
}
|
|
|
|
|
@@ -526,7 +534,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
else
|
|
|
strcpy(pcm->name, "USB Audio");
|
|
|
|
|
|
- snd_usb_init_substream(as, stream, fp);
|
|
|
+ snd_usb_init_substream(as, stream, fp, pd);
|
|
|
|
|
|
/*
|
|
|
* Keep using head insertion for M-Audio Audiophile USB (tm) which has a
|
|
@@ -544,6 +552,21 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
return add_chmap(pcm, stream, &as->substream[stream]);
|
|
|
}
|
|
|
|
|
|
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
|
|
|
+ int stream,
|
|
|
+ struct audioformat *fp)
|
|
|
+{
|
|
|
+ return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
|
|
|
+ int stream,
|
|
|
+ struct audioformat *fp,
|
|
|
+ struct snd_usb_power_domain *pd)
|
|
|
+{
|
|
|
+ return __snd_usb_add_audio_stream(chip, stream, fp, pd);
|
|
|
+}
|
|
|
+
|
|
|
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
|
|
|
struct usb_host_interface *alts,
|
|
|
int protocol, int iface_no)
|
|
@@ -819,6 +842,7 @@ found_clock:
|
|
|
static struct audioformat *
|
|
|
snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
|
|
|
struct usb_host_interface *alts,
|
|
|
+ struct snd_usb_power_domain **pd_out,
|
|
|
int iface_no, int altset_idx,
|
|
|
int altno, int stream)
|
|
|
{
|
|
@@ -829,6 +853,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
|
|
|
struct uac3_as_header_descriptor *as = NULL;
|
|
|
struct uac3_hc_descriptor_header hc_header;
|
|
|
struct snd_pcm_chmap_elem *chmap;
|
|
|
+ struct snd_usb_power_domain *pd;
|
|
|
unsigned char badd_profile;
|
|
|
u64 badd_formats = 0;
|
|
|
unsigned int num_channels;
|
|
@@ -1008,12 +1033,28 @@ found_clock:
|
|
|
fp->rate_max = UAC3_BADD_SAMPLING_RATE;
|
|
|
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
|
|
|
|
|
|
+ pd = kzalloc(sizeof(pd), GFP_KERNEL);
|
|
|
+ if (!pd) {
|
|
|
+ kfree(fp->rate_table);
|
|
|
+ kfree(fp);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
|
+ 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;
|
|
|
+
|
|
|
} else {
|
|
|
fp->attributes = parse_uac_endpoint_attributes(chip, alts,
|
|
|
UAC_VERSION_3,
|
|
|
iface_no);
|
|
|
+
|
|
|
+ pd = snd_usb_find_power_domain(chip->ctrl_intf,
|
|
|
+ as->bTerminalLink);
|
|
|
+
|
|
|
/* ok, let's parse further... */
|
|
|
if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
|
|
|
+ kfree(pd);
|
|
|
kfree(fp->chmap);
|
|
|
kfree(fp->rate_table);
|
|
|
kfree(fp);
|
|
@@ -1021,6 +1062,9 @@ found_clock:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (pd)
|
|
|
+ *pd_out = pd;
|
|
|
+
|
|
|
return fp;
|
|
|
}
|
|
|
|
|
@@ -1032,6 +1076,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
|
|
struct usb_interface_descriptor *altsd;
|
|
|
int i, altno, err, stream;
|
|
|
struct audioformat *fp = NULL;
|
|
|
+ struct snd_usb_power_domain *pd = NULL;
|
|
|
int num, protocol;
|
|
|
|
|
|
dev = chip->dev;
|
|
@@ -1114,7 +1159,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
|
|
break;
|
|
|
}
|
|
|
case UAC_VERSION_3:
|
|
|
- fp = snd_usb_get_audioformat_uac3(chip, alts,
|
|
|
+ fp = snd_usb_get_audioformat_uac3(chip, alts, &pd,
|
|
|
iface_no, i, altno, stream);
|
|
|
break;
|
|
|
}
|
|
@@ -1125,9 +1170,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
|
|
return PTR_ERR(fp);
|
|
|
|
|
|
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
|
|
|
- err = snd_usb_add_audio_stream(chip, stream, fp);
|
|
|
+ if (protocol == UAC_VERSION_3)
|
|
|
+ err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
|
|
|
+ else
|
|
|
+ err = snd_usb_add_audio_stream(chip, stream, fp);
|
|
|
+
|
|
|
if (err < 0) {
|
|
|
list_del(&fp->list); /* unlink for avoiding double-free */
|
|
|
+ kfree(pd);
|
|
|
kfree(fp->rate_table);
|
|
|
kfree(fp->chmap);
|
|
|
kfree(fp);
|