aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-11-26 10:24:02 -0500
committerTakashi Iwai <tiwai@suse.de>2012-11-26 10:24:02 -0500
commit04324ccc75f96b3ed7aad1c866d1b7925e977bdf (patch)
tree8ac8f049686de15f2241ea991f03a79d663dc65e /sound/usb
parent7cc17a31ff5ca3d8e1719af88907beec7b1fd24e (diff)
ALSA: usb-audio: add channel map support
Add the support for channel maps of the PCM streams on USB audio devices. The channel map information is already found in ChannelConfig descriptor entries, which haven't been referred until now. Each chmap entry is added to audioformat list entry and copied to TLV dynamically instead of creating a whole chmap array. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/stream.c230
2 files changed, 227 insertions, 5 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 814cb357ff88..8a751b4887ea 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -27,6 +27,7 @@ struct audioformat {
27 unsigned int nr_rates; /* number of rate table entries */ 27 unsigned int nr_rates; /* number of rate table entries */
28 unsigned int *rate_table; /* rate table */ 28 unsigned int *rate_table; /* rate table */
29 unsigned char clock; /* associated clock */ 29 unsigned char clock; /* associated clock */
30 struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */
30}; 31};
31 32
32struct snd_usb_substream; 33struct snd_usb_substream;
@@ -109,6 +110,7 @@ struct snd_usb_substream {
109 struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ 110 struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
110 snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ 111 snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */
111 unsigned int channels; /* current number of channels (for hw_params callback) */ 112 unsigned int channels; /* current number of channels (for hw_params callback) */
113 unsigned int channels_max; /* max channels in the all audiofmts */
112 unsigned int cur_rate; /* current rate (for hw_params callback) */ 114 unsigned int cur_rate; /* current rate (for hw_params callback) */
113 unsigned int period_bytes; /* current period bytes (for hw_params callback) */ 115 unsigned int period_bytes; /* current period bytes (for hw_params callback) */
114 unsigned int altset_idx; /* USB data format: index of alternate setting */ 116 unsigned int altset_idx; /* USB data format: index of alternate setting */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 1de0c8c002a8..ad181d538bd9 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -23,6 +23,8 @@
23 23
24#include <sound/core.h> 24#include <sound/core.h>
25#include <sound/pcm.h> 25#include <sound/pcm.h>
26#include <sound/control.h>
27#include <sound/tlv.h>
26 28
27#include "usbaudio.h" 29#include "usbaudio.h"
28#include "card.h" 30#include "card.h"
@@ -47,6 +49,7 @@ static void free_substream(struct snd_usb_substream *subs)
47 list_for_each_safe(p, n, &subs->fmt_list) { 49 list_for_each_safe(p, n, &subs->fmt_list) {
48 struct audioformat *fp = list_entry(p, struct audioformat, list); 50 struct audioformat *fp = list_entry(p, struct audioformat, list);
49 kfree(fp->rate_table); 51 kfree(fp->rate_table);
52 kfree(fp->chmap);
50 kfree(fp); 53 kfree(fp);
51 } 54 }
52 kfree(subs->rate_list.list); 55 kfree(subs->rate_list.list);
@@ -99,6 +102,206 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
99 subs->num_formats++; 102 subs->num_formats++;
100 subs->fmt_type = fp->fmt_type; 103 subs->fmt_type = fp->fmt_type;
101 subs->ep_num = fp->endpoint; 104 subs->ep_num = fp->endpoint;
105 if (fp->channels > subs->channels_max)
106 subs->channels_max = fp->channels;
107}
108
109/* kctl callbacks for usb-audio channel maps */
110static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol,
111 struct snd_ctl_elem_info *uinfo)
112{
113 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
114 struct snd_usb_substream *subs = info->private_data;
115
116 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
117 uinfo->count = subs->channels_max;
118 uinfo->value.integer.min = 0;
119 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
120 return 0;
121}
122
123/* check whether a duplicated entry exists in the audiofmt list */
124static bool have_dup_chmap(struct snd_usb_substream *subs,
125 struct audioformat *fp)
126{
127 struct list_head *p;
128
129 for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) {
130 struct audioformat *prev;
131 prev = list_entry(p, struct audioformat, list);
132 if (prev->chmap &&
133 !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap)))
134 return true;
135 }
136 return false;
137}
138
139static int usb_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
140 unsigned int size, unsigned int __user *tlv)
141{
142 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
143 struct snd_usb_substream *subs = info->private_data;
144 struct audioformat *fp;
145 unsigned int __user *dst;
146 int count = 0;
147
148 if (size < 8)
149 return -ENOMEM;
150 if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
151 return -EFAULT;
152 size -= 8;
153 dst = tlv + 2;
154 list_for_each_entry(fp, &subs->fmt_list, list) {
155 int i, ch_bytes;
156
157 if (!fp->chmap)
158 continue;
159 if (have_dup_chmap(subs, fp))
160 continue;
161 /* copy the entry */
162 ch_bytes = fp->chmap->channels * 4;
163 if (size < 8 + ch_bytes)
164 return -ENOMEM;
165 if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
166 put_user(ch_bytes, dst + 1))
167 return -EFAULT;
168 dst += 2;
169 for (i = 0; i < fp->chmap->channels; i++, dst++) {
170 if (put_user(fp->chmap->map[i], dst))
171 return -EFAULT;
172 }
173
174 count += 8 + ch_bytes;
175 size -= 8 + ch_bytes;
176 }
177 if (put_user(count, tlv + 1))
178 return -EFAULT;
179 return 0;
180}
181
182static int usb_chmap_ctl_get(struct snd_kcontrol *kcontrol,
183 struct snd_ctl_elem_value *ucontrol)
184{
185 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
186 struct snd_usb_substream *subs = info->private_data;
187 struct snd_pcm_chmap_elem *chmap = NULL;
188 int i;
189
190 memset(ucontrol->value.integer.value, 0,
191 sizeof(ucontrol->value.integer.value));
192 if (subs->cur_audiofmt)
193 chmap = subs->cur_audiofmt->chmap;
194 if (chmap) {
195 for (i = 0; i < chmap->channels; i++)
196 ucontrol->value.integer.value[i] = chmap->map[i];
197 }
198 return 0;
199}
200
201/* create a chmap kctl assigned to the given USB substream */
202static int add_chmap(struct snd_pcm *pcm, int stream,
203 struct snd_usb_substream *subs)
204{
205 struct audioformat *fp;
206 struct snd_pcm_chmap *chmap;
207 struct snd_kcontrol *kctl;
208 int err;
209
210 list_for_each_entry(fp, &subs->fmt_list, list)
211 if (fp->chmap)
212 goto ok;
213 /* no chmap is found */
214 return 0;
215
216 ok:
217 err = snd_pcm_add_chmap_ctls(pcm, stream, NULL, 0, 0, &chmap);
218 if (err < 0)
219 return err;
220
221 /* override handlers */
222 chmap->private_data = subs;
223 kctl = chmap->kctl;
224 kctl->info = usb_chmap_ctl_info;
225 kctl->get = usb_chmap_ctl_get;
226 kctl->tlv.c = usb_chmap_ctl_tlv;
227
228 return 0;
229}
230
231/* convert from USB ChannelConfig bits to ALSA chmap element */
232static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
233 int protocol)
234{
235 static unsigned int uac1_maps[] = {
236 SNDRV_CHMAP_FL, /* left front */
237 SNDRV_CHMAP_FR, /* right front */
238 SNDRV_CHMAP_FC, /* center front */
239 SNDRV_CHMAP_LFE, /* LFE */
240 SNDRV_CHMAP_SL, /* left surround */
241 SNDRV_CHMAP_SR, /* right surround */
242 SNDRV_CHMAP_FLC, /* left of center */
243 SNDRV_CHMAP_FRC, /* right of center */
244 SNDRV_CHMAP_RC, /* surround */
245 SNDRV_CHMAP_SL, /* side left */
246 SNDRV_CHMAP_SR, /* side right */
247 SNDRV_CHMAP_TC, /* top */
248 0 /* terminator */
249 };
250 static unsigned int uac2_maps[] = {
251 SNDRV_CHMAP_FL, /* front left */
252 SNDRV_CHMAP_FR, /* front right */
253 SNDRV_CHMAP_FC, /* front center */
254 SNDRV_CHMAP_LFE, /* LFE */
255 SNDRV_CHMAP_RL, /* back left */
256 SNDRV_CHMAP_RR, /* back right */
257 SNDRV_CHMAP_FLC, /* front left of center */
258 SNDRV_CHMAP_FRC, /* front right of center */
259 SNDRV_CHMAP_RC, /* back center */
260 SNDRV_CHMAP_SL, /* side left */
261 SNDRV_CHMAP_SR, /* side right */
262 SNDRV_CHMAP_TC, /* top center */
263 SNDRV_CHMAP_TFL, /* top front left */
264 SNDRV_CHMAP_TFC, /* top front center */
265 SNDRV_CHMAP_TFR, /* top front right */
266 SNDRV_CHMAP_TRL, /* top back left */
267 SNDRV_CHMAP_TRC, /* top back center */
268 SNDRV_CHMAP_TRR, /* top back right */
269 SNDRV_CHMAP_TFLC, /* top front left of center */
270 SNDRV_CHMAP_TFRC, /* top front right of center */
271 SNDRV_CHMAP_LLFE, /* left LFE */
272 SNDRV_CHMAP_RLFE, /* right LFE */
273 SNDRV_CHMAP_TSL, /* top side left */
274 SNDRV_CHMAP_TSR, /* top side right */
275 SNDRV_CHMAP_BC, /* bottom center */
276 SNDRV_CHMAP_BLC, /* bottom left center */
277 SNDRV_CHMAP_BRC, /* bottom right center */
278 0 /* terminator */
279 };
280 struct snd_pcm_chmap_elem *chmap;
281 const unsigned int *maps;
282 int c;
283
284 if (!bits)
285 return NULL;
286 if (channels > ARRAY_SIZE(chmap->map))
287 return NULL;
288
289 chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
290 if (!chmap)
291 return NULL;
292
293 maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps;
294 chmap->channels = channels;
295 c = 0;
296 for (; bits && *maps; maps++, bits >>= 1) {
297 if (bits & 1)
298 chmap->map[c++] = *maps;
299 }
300
301 for (; c < channels; c++)
302 chmap->map[c] = SNDRV_CHMAP_UNKNOWN;
303
304 return chmap;
102} 305}
103 306
104/* 307/*
@@ -140,7 +343,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
140 if (err < 0) 343 if (err < 0)
141 return err; 344 return err;
142 snd_usb_init_substream(as, stream, fp); 345 snd_usb_init_substream(as, stream, fp);
143 return 0; 346 return add_chmap(as->pcm, stream, subs);
144 } 347 }
145 348
146 /* create a new pcm */ 349 /* create a new pcm */
@@ -174,7 +377,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
174 377
175 snd_usb_proc_pcm_format_add(as); 378 snd_usb_proc_pcm_format_add(as);
176 379
177 return 0; 380 return add_chmap(pcm, stream, &as->substream[stream]);
178} 381}
179 382
180static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, 383static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
@@ -218,8 +421,11 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
218 return attributes; 421 return attributes;
219} 422}
220 423
221static struct uac2_input_terminal_descriptor * 424/* find an input terminal descriptor (either UAC1 or UAC2) with the given
222 snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, 425 * terminal id
426 */
427static void *
428snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
223 int terminal_id) 429 int terminal_id)
224{ 430{
225 struct uac2_input_terminal_descriptor *term = NULL; 431 struct uac2_input_terminal_descriptor *term = NULL;
@@ -261,6 +467,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
261 struct audioformat *fp = NULL; 467 struct audioformat *fp = NULL;
262 int num, protocol, clock = 0; 468 int num, protocol, clock = 0;
263 struct uac_format_type_i_continuous_descriptor *fmt; 469 struct uac_format_type_i_continuous_descriptor *fmt;
470 unsigned int chconfig;
264 471
265 dev = chip->dev; 472 dev = chip->dev;
266 473
@@ -300,6 +507,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
300 if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) 507 if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
301 continue; 508 continue;
302 509
510 chconfig = 0;
303 /* get audio formats */ 511 /* get audio formats */
304 switch (protocol) { 512 switch (protocol) {
305 default: 513 default:
@@ -311,6 +519,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
311 case UAC_VERSION_1: { 519 case UAC_VERSION_1: {
312 struct uac1_as_header_descriptor *as = 520 struct uac1_as_header_descriptor *as =
313 snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); 521 snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
522 struct uac_input_terminal_descriptor *iterm;
314 523
315 if (!as) { 524 if (!as) {
316 snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", 525 snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
@@ -325,6 +534,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
325 } 534 }
326 535
327 format = le16_to_cpu(as->wFormatTag); /* remember the format value */ 536 format = le16_to_cpu(as->wFormatTag); /* remember the format value */
537
538 iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
539 as->bTerminalLink);
540 if (iterm) {
541 num_channels = iterm->bNrChannels;
542 chconfig = le16_to_cpu(iterm->wChannelConfig);
543 }
544
328 break; 545 break;
329 } 546 }
330 547
@@ -355,6 +572,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
355 as->bTerminalLink); 572 as->bTerminalLink);
356 if (input_term) { 573 if (input_term) {
357 clock = input_term->bCSourceID; 574 clock = input_term->bCSourceID;
575 chconfig = le32_to_cpu(input_term->bmChannelConfig);
358 break; 576 break;
359 } 577 }
360 578
@@ -413,13 +631,13 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
413 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; 631 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
414 fp->datainterval = snd_usb_parse_datainterval(chip, alts); 632 fp->datainterval = snd_usb_parse_datainterval(chip, alts);
415 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); 633 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
416 /* num_channels is only set for v2 interfaces */
417 fp->channels = num_channels; 634 fp->channels = num_channels;
418 if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) 635 if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
419 fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) 636 fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
420 * (fp->maxpacksize & 0x7ff); 637 * (fp->maxpacksize & 0x7ff);
421 fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); 638 fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
422 fp->clock = clock; 639 fp->clock = clock;
640 fp->chmap = convert_chmap(num_channels, chconfig, protocol);
423 641
424 /* some quirks for attributes here */ 642 /* some quirks for attributes here */
425 643
@@ -455,6 +673,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
455 /* ok, let's parse further... */ 673 /* ok, let's parse further... */
456 if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { 674 if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
457 kfree(fp->rate_table); 675 kfree(fp->rate_table);
676 kfree(fp->chmap);
458 kfree(fp); 677 kfree(fp);
459 fp = NULL; 678 fp = NULL;
460 continue; 679 continue;
@@ -464,6 +683,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
464 err = snd_usb_add_audio_stream(chip, stream, fp); 683 err = snd_usb_add_audio_stream(chip, stream, fp);
465 if (err < 0) { 684 if (err < 0) {
466 kfree(fp->rate_table); 685 kfree(fp->rate_table);
686 kfree(fp->chmap);
467 kfree(fp); 687 kfree(fp);
468 return err; 688 return err;
469 } 689 }