summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJorge Sanjuan <jorge.sanjuan@codethink.co.uk>2018-07-31 08:28:43 -0400
committerTakashi Iwai <tiwai@suse.de>2018-07-31 09:01:30 -0400
commit7edf3b5e6a4544b42d3572a7058f8ffe96349ee8 (patch)
tree3e19f5b92d3e3cddfd0c8401b90e9709557f6163
parent11785ef53228d23ec386f5fe4a34601536f0c891 (diff)
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 <jorge.sanjuan@codethink.co.uk> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/stream.c66
2 files changed, 60 insertions, 8 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 9b41b7dda84f..ac785d15ced4 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -37,6 +37,7 @@ struct audioformat {
37 37
38struct snd_usb_substream; 38struct snd_usb_substream;
39struct snd_usb_endpoint; 39struct snd_usb_endpoint;
40struct snd_usb_power_domain;
40 41
41struct snd_urb_ctx { 42struct snd_urb_ctx {
42 struct urb *urb; 43 struct urb *urb;
@@ -115,6 +116,7 @@ struct snd_usb_substream {
115 int interface; /* current interface */ 116 int interface; /* current interface */
116 int endpoint; /* assigned endpoint */ 117 int endpoint; /* assigned endpoint */
117 struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ 118 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 */
118 snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ 120 snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */
119 unsigned int channels; /* current number of channels (for hw_params callback) */ 121 unsigned int channels; /* current number of channels (for hw_params callback) */
120 unsigned int channels_max; /* max channels in the all audiofmts */ 122 unsigned int channels_max; /* max channels in the all audiofmts */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 729afd808cc4..c0567fa1e84b 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -37,6 +37,7 @@
37#include "format.h" 37#include "format.h"
38#include "clock.h" 38#include "clock.h"
39#include "stream.h" 39#include "stream.h"
40#include "power.h"
40 41
41/* 42/*
42 * free a substream 43 * free a substream
@@ -53,6 +54,7 @@ static void free_substream(struct snd_usb_substream *subs)
53 kfree(fp); 54 kfree(fp);
54 } 55 }
55 kfree(subs->rate_list.list); 56 kfree(subs->rate_list.list);
57 kfree(subs->str_pd);
56} 58}
57 59
58 60
@@ -82,7 +84,8 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
82 84
83static void snd_usb_init_substream(struct snd_usb_stream *as, 85static void snd_usb_init_substream(struct snd_usb_stream *as,
84 int stream, 86 int stream,
85 struct audioformat *fp) 87 struct audioformat *fp,
88 struct snd_usb_power_domain *pd)
86{ 89{
87 struct snd_usb_substream *subs = &as->substream[stream]; 90 struct snd_usb_substream *subs = &as->substream[stream];
88 91
@@ -107,6 +110,9 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
107 if (fp->channels > subs->channels_max) 110 if (fp->channels > subs->channels_max)
108 subs->channels_max = fp->channels; 111 subs->channels_max = fp->channels;
109 112
113 if (pd)
114 subs->str_pd = pd;
115
110 snd_usb_preallocate_buffer(subs); 116 snd_usb_preallocate_buffer(subs);
111} 117}
112 118
@@ -468,9 +474,11 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
468 * fmt_list and will be freed on the chip instance release. do not free 474 * fmt_list and will be freed on the chip instance release. do not free
469 * fp or do remove it from the substream fmt_list to avoid double-free. 475 * fp or do remove it from the substream fmt_list to avoid double-free.
470 */ 476 */
471int snd_usb_add_audio_stream(struct snd_usb_audio *chip, 477static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
472 int stream, 478 int stream,
473 struct audioformat *fp) 479 struct audioformat *fp,
480 struct snd_usb_power_domain *pd)
481
474{ 482{
475 struct snd_usb_stream *as; 483 struct snd_usb_stream *as;
476 struct snd_usb_substream *subs; 484 struct snd_usb_substream *subs;
@@ -498,7 +506,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
498 err = snd_pcm_new_stream(as->pcm, stream, 1); 506 err = snd_pcm_new_stream(as->pcm, stream, 1);
499 if (err < 0) 507 if (err < 0)
500 return err; 508 return err;
501 snd_usb_init_substream(as, stream, fp); 509 snd_usb_init_substream(as, stream, fp, pd);
502 return add_chmap(as->pcm, stream, subs); 510 return add_chmap(as->pcm, stream, subs);
503 } 511 }
504 512
@@ -526,7 +534,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
526 else 534 else
527 strcpy(pcm->name, "USB Audio"); 535 strcpy(pcm->name, "USB Audio");
528 536
529 snd_usb_init_substream(as, stream, fp); 537 snd_usb_init_substream(as, stream, fp, pd);
530 538
531 /* 539 /*
532 * Keep using head insertion for M-Audio Audiophile USB (tm) which has a 540 * 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,
544 return add_chmap(pcm, stream, &as->substream[stream]); 552 return add_chmap(pcm, stream, &as->substream[stream]);
545} 553}
546 554
555int 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
562static 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
547static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, 570static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
548 struct usb_host_interface *alts, 571 struct usb_host_interface *alts,
549 int protocol, int iface_no) 572 int protocol, int iface_no)
@@ -819,6 +842,7 @@ found_clock:
819static struct audioformat * 842static struct audioformat *
820snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, 843snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
821 struct usb_host_interface *alts, 844 struct usb_host_interface *alts,
845 struct snd_usb_power_domain **pd_out,
822 int iface_no, int altset_idx, 846 int iface_no, int altset_idx,
823 int altno, int stream) 847 int altno, int stream)
824{ 848{
@@ -829,6 +853,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
829 struct uac3_as_header_descriptor *as = NULL; 853 struct uac3_as_header_descriptor *as = NULL;
830 struct uac3_hc_descriptor_header hc_header; 854 struct uac3_hc_descriptor_header hc_header;
831 struct snd_pcm_chmap_elem *chmap; 855 struct snd_pcm_chmap_elem *chmap;
856 struct snd_usb_power_domain *pd;
832 unsigned char badd_profile; 857 unsigned char badd_profile;
833 u64 badd_formats = 0; 858 u64 badd_formats = 0;
834 unsigned int num_channels; 859 unsigned int num_channels;
@@ -1008,12 +1033,28 @@ found_clock:
1008 fp->rate_max = UAC3_BADD_SAMPLING_RATE; 1033 fp->rate_max = UAC3_BADD_SAMPLING_RATE;
1009 fp->rates = SNDRV_PCM_RATE_CONTINUOUS; 1034 fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
1010 1035
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
1011 } else { 1047 } else {
1012 fp->attributes = parse_uac_endpoint_attributes(chip, alts, 1048 fp->attributes = parse_uac_endpoint_attributes(chip, alts,
1013 UAC_VERSION_3, 1049 UAC_VERSION_3,
1014 iface_no); 1050 iface_no);
1051
1052 pd = snd_usb_find_power_domain(chip->ctrl_intf,
1053 as->bTerminalLink);
1054
1015 /* ok, let's parse further... */ 1055 /* ok, let's parse further... */
1016 if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { 1056 if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
1057 kfree(pd);
1017 kfree(fp->chmap); 1058 kfree(fp->chmap);
1018 kfree(fp->rate_table); 1059 kfree(fp->rate_table);
1019 kfree(fp); 1060 kfree(fp);
@@ -1021,6 +1062,9 @@ found_clock:
1021 } 1062 }
1022 } 1063 }
1023 1064
1065 if (pd)
1066 *pd_out = pd;
1067
1024 return fp; 1068 return fp;
1025} 1069}
1026 1070
@@ -1032,6 +1076,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
1032 struct usb_interface_descriptor *altsd; 1076 struct usb_interface_descriptor *altsd;
1033 int i, altno, err, stream; 1077 int i, altno, err, stream;
1034 struct audioformat *fp = NULL; 1078 struct audioformat *fp = NULL;
1079 struct snd_usb_power_domain *pd = NULL;
1035 int num, protocol; 1080 int num, protocol;
1036 1081
1037 dev = chip->dev; 1082 dev = chip->dev;
@@ -1114,7 +1159,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
1114 break; 1159 break;
1115 } 1160 }
1116 case UAC_VERSION_3: 1161 case UAC_VERSION_3:
1117 fp = snd_usb_get_audioformat_uac3(chip, alts, 1162 fp = snd_usb_get_audioformat_uac3(chip, alts, &pd,
1118 iface_no, i, altno, stream); 1163 iface_no, i, altno, stream);
1119 break; 1164 break;
1120 } 1165 }
@@ -1125,9 +1170,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
1125 return PTR_ERR(fp); 1170 return PTR_ERR(fp);
1126 1171
1127 dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); 1172 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
1129 if (err < 0) { 1178 if (err < 0) {
1130 list_del(&fp->list); /* unlink for avoiding double-free */ 1179 list_del(&fp->list); /* unlink for avoiding double-free */
1180 kfree(pd);
1131 kfree(fp->rate_table); 1181 kfree(fp->rate_table);
1132 kfree(fp->chmap); 1182 kfree(fp->chmap);
1133 kfree(fp); 1183 kfree(fp);