Skip to content

Commit 7edf3b5

Browse files
Jorge Sanjuantiwai
authored andcommitted
ALSA: usb-audio: AudioStreaming Power Domain parsing
Power Domains in the UAC3 spec are mainly intended to be associated to an Input or Output Terminal so the host changes the power state of the entire capture or playback path within the topology. This patch adds support for finding Power Domains associated to an Audio Streaming Interface (bTerminalLink) and adds a reference to them in the usb audio substreams (snd_usb_substream). Signed-off-by: Jorge Sanjuan <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 11785ef commit 7edf3b5

File tree

2 files changed

+60
-8
lines changed

2 files changed

+60
-8
lines changed

sound/usb/card.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct audioformat {
3737

3838
struct snd_usb_substream;
3939
struct snd_usb_endpoint;
40+
struct snd_usb_power_domain;
4041

4142
struct snd_urb_ctx {
4243
struct urb *urb;
@@ -115,6 +116,7 @@ struct snd_usb_substream {
115116
int interface; /* current interface */
116117
int endpoint; /* assigned endpoint */
117118
struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
119+
struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */
118120
snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */
119121
unsigned int channels; /* current number of channels (for hw_params callback) */
120122
unsigned int channels_max; /* max channels in the all audiofmts */

sound/usb/stream.c

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "format.h"
3838
#include "clock.h"
3939
#include "stream.h"
40+
#include "power.h"
4041

4142
/*
4243
* free a substream
@@ -53,6 +54,7 @@ static void free_substream(struct snd_usb_substream *subs)
5354
kfree(fp);
5455
}
5556
kfree(subs->rate_list.list);
57+
kfree(subs->str_pd);
5658
}
5759

5860

@@ -82,7 +84,8 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
8284

8385
static void snd_usb_init_substream(struct snd_usb_stream *as,
8486
int stream,
85-
struct audioformat *fp)
87+
struct audioformat *fp,
88+
struct snd_usb_power_domain *pd)
8689
{
8790
struct snd_usb_substream *subs = &as->substream[stream];
8891

@@ -107,6 +110,9 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
107110
if (fp->channels > subs->channels_max)
108111
subs->channels_max = fp->channels;
109112

113+
if (pd)
114+
subs->str_pd = pd;
115+
110116
snd_usb_preallocate_buffer(subs);
111117
}
112118

@@ -468,9 +474,11 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
468474
* fmt_list and will be freed on the chip instance release. do not free
469475
* fp or do remove it from the substream fmt_list to avoid double-free.
470476
*/
471-
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
472-
int stream,
473-
struct audioformat *fp)
477+
static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
478+
int stream,
479+
struct audioformat *fp,
480+
struct snd_usb_power_domain *pd)
481+
474482
{
475483
struct snd_usb_stream *as;
476484
struct snd_usb_substream *subs;
@@ -498,7 +506,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
498506
err = snd_pcm_new_stream(as->pcm, stream, 1);
499507
if (err < 0)
500508
return err;
501-
snd_usb_init_substream(as, stream, fp);
509+
snd_usb_init_substream(as, stream, fp, pd);
502510
return add_chmap(as->pcm, stream, subs);
503511
}
504512

@@ -526,7 +534,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
526534
else
527535
strcpy(pcm->name, "USB Audio");
528536

529-
snd_usb_init_substream(as, stream, fp);
537+
snd_usb_init_substream(as, stream, fp, pd);
530538

531539
/*
532540
* 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,
544552
return add_chmap(pcm, stream, &as->substream[stream]);
545553
}
546554

555+
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
556+
int stream,
557+
struct audioformat *fp)
558+
{
559+
return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
560+
}
561+
562+
static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
563+
int stream,
564+
struct audioformat *fp,
565+
struct snd_usb_power_domain *pd)
566+
{
567+
return __snd_usb_add_audio_stream(chip, stream, fp, pd);
568+
}
569+
547570
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
548571
struct usb_host_interface *alts,
549572
int protocol, int iface_no)
@@ -819,6 +842,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
819842
static struct audioformat *
820843
snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
821844
struct usb_host_interface *alts,
845+
struct snd_usb_power_domain **pd_out,
822846
int iface_no, int altset_idx,
823847
int altno, int stream)
824848
{
@@ -829,6 +853,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
829853
struct uac3_as_header_descriptor *as = NULL;
830854
struct uac3_hc_descriptor_header hc_header;
831855
struct snd_pcm_chmap_elem *chmap;
856+
struct snd_usb_power_domain *pd;
832857
unsigned char badd_profile;
833858
u64 badd_formats = 0;
834859
unsigned int num_channels;
@@ -1008,19 +1033,38 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
10081033
fp->rate_max = UAC3_BADD_SAMPLING_RATE;
10091034
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
10101035

1036+
pd = kzalloc(sizeof(pd), GFP_KERNEL);
1037+
if (!pd) {
1038+
kfree(fp->rate_table);
1039+
kfree(fp);
1040+
return NULL;
1041+
}
1042+
pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
1043+
UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11;
1044+
pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0;
1045+
pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0;
1046+
10111047
} else {
10121048
fp->attributes = parse_uac_endpoint_attributes(chip, alts,
10131049
UAC_VERSION_3,
10141050
iface_no);
1051+
1052+
pd = snd_usb_find_power_domain(chip->ctrl_intf,
1053+
as->bTerminalLink);
1054+
10151055
/* ok, let's parse further... */
10161056
if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
1057+
kfree(pd);
10171058
kfree(fp->chmap);
10181059
kfree(fp->rate_table);
10191060
kfree(fp);
10201061
return NULL;
10211062
}
10221063
}
10231064

1065+
if (pd)
1066+
*pd_out = pd;
1067+
10241068
return fp;
10251069
}
10261070

@@ -1032,6 +1076,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
10321076
struct usb_interface_descriptor *altsd;
10331077
int i, altno, err, stream;
10341078
struct audioformat *fp = NULL;
1079+
struct snd_usb_power_domain *pd = NULL;
10351080
int num, protocol;
10361081

10371082
dev = chip->dev;
@@ -1114,7 +1159,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
11141159
break;
11151160
}
11161161
case UAC_VERSION_3:
1117-
fp = snd_usb_get_audioformat_uac3(chip, alts,
1162+
fp = snd_usb_get_audioformat_uac3(chip, alts, &pd,
11181163
iface_no, i, altno, stream);
11191164
break;
11201165
}
@@ -1125,9 +1170,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
11251170
return PTR_ERR(fp);
11261171

11271172
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
1128-
err = snd_usb_add_audio_stream(chip, stream, fp);
1173+
if (protocol == UAC_VERSION_3)
1174+
err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
1175+
else
1176+
err = snd_usb_add_audio_stream(chip, stream, fp);
1177+
11291178
if (err < 0) {
11301179
list_del(&fp->list); /* unlink for avoiding double-free */
1180+
kfree(pd);
11311181
kfree(fp->rate_table);
11321182
kfree(fp->chmap);
11331183
kfree(fp);

0 commit comments

Comments
 (0)