aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/format.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-03-04 13:46:16 -0500
committerTakashi Iwai <tiwai@suse.de>2010-03-05 02:18:54 -0500
commit29088fef3e3f62147c1dd53d764da4f04bf3188d (patch)
treeb8da9e5171427315a9d50be8fa5a2537f651c5c1 /sound/usb/format.c
parent015eb0b08150c6fef843efe22609589ead3d4fb8 (diff)
ALSA: usb-audio: support multiple formats with audio class v2 devices
Change the parser to correctly handle v2 descriptors with multiple format bits set. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/format.c')
-rw-r--r--sound/usb/format.c93
1 files changed, 38 insertions, 55 deletions
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 87f07f042c63..b613e0aaeb63 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -37,19 +37,20 @@
37 * @format: the format tag (wFormatTag) 37 * @format: the format tag (wFormatTag)
38 * @fmt: the format type descriptor 38 * @fmt: the format type descriptor
39 */ 39 */
40static int parse_audio_format_i_type(struct snd_usb_audio *chip, 40static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
41 struct audioformat *fp, 41 struct audioformat *fp,
42 int format, void *_fmt, 42 int format, void *_fmt,
43 int protocol) 43 int protocol)
44{ 44{
45 int pcm_format, i;
46 int sample_width, sample_bytes; 45 int sample_width, sample_bytes;
46 u64 pcm_formats;
47 47
48 switch (protocol) { 48 switch (protocol) {
49 case UAC_VERSION_1: { 49 case UAC_VERSION_1: {
50 struct uac_format_type_i_discrete_descriptor *fmt = _fmt; 50 struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
51 sample_width = fmt->bBitResolution; 51 sample_width = fmt->bBitResolution;
52 sample_bytes = fmt->bSubframeSize; 52 sample_bytes = fmt->bSubframeSize;
53 format = 1 << format;
53 break; 54 break;
54 } 55 }
55 56
@@ -57,24 +58,7 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip,
57 struct uac_format_type_i_ext_descriptor *fmt = _fmt; 58 struct uac_format_type_i_ext_descriptor *fmt = _fmt;
58 sample_width = fmt->bBitResolution; 59 sample_width = fmt->bBitResolution;
59 sample_bytes = fmt->bSubslotSize; 60 sample_bytes = fmt->bSubslotSize;
60 61 format <<= 1;
61 /*
62 * FIXME
63 * USB audio class v2 devices specify a bitmap of possible
64 * audio formats rather than one fix value. For now, we just
65 * pick one of them and report that as the only possible
66 * value for this setting.
67 * The bit allocation map is in fact compatible to the
68 * wFormatTag of the v1 AS streaming descriptors, which is why
69 * we can simply map the matrix.
70 */
71
72 for (i = 0; i < 5; i++)
73 if (format & (1UL << i)) {
74 format = i + 1;
75 break;
76 }
77
78 break; 62 break;
79 } 63 }
80 64
@@ -82,15 +66,15 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip,
82 return -EINVAL; 66 return -EINVAL;
83 } 67 }
84 68
85 /* FIXME: correct endianess and sign? */ 69 pcm_formats = 0;
86 pcm_format = -1;
87 70
88 switch (format) { 71 if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) {
89 case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */ 72 /* some devices don't define this correctly... */
90 snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", 73 snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
91 chip->dev->devnum, fp->iface, fp->altsetting); 74 chip->dev->devnum, fp->iface, fp->altsetting);
92 /* fall-through */ 75 format = 1 << UAC_FORMAT_TYPE_I_PCM;
93 case UAC_FORMAT_TYPE_I_PCM: 76 }
77 if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
94 if (sample_width > sample_bytes * 8) { 78 if (sample_width > sample_bytes * 8) {
95 snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", 79 snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
96 chip->dev->devnum, fp->iface, fp->altsetting, 80 chip->dev->devnum, fp->iface, fp->altsetting,
@@ -99,22 +83,22 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip,
99 /* check the format byte size */ 83 /* check the format byte size */
100 switch (sample_bytes) { 84 switch (sample_bytes) {
101 case 1: 85 case 1:
102 pcm_format = SNDRV_PCM_FORMAT_S8; 86 pcm_formats |= SNDRV_PCM_FMTBIT_S8;
103 break; 87 break;
104 case 2: 88 case 2:
105 if (snd_usb_is_big_endian_format(chip, fp)) 89 if (snd_usb_is_big_endian_format(chip, fp))
106 pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ 90 pcm_formats |= SNDRV_PCM_FMTBIT_S16_BE; /* grrr, big endian!! */
107 else 91 else
108 pcm_format = SNDRV_PCM_FORMAT_S16_LE; 92 pcm_formats |= SNDRV_PCM_FMTBIT_S16_LE;
109 break; 93 break;
110 case 3: 94 case 3:
111 if (snd_usb_is_big_endian_format(chip, fp)) 95 if (snd_usb_is_big_endian_format(chip, fp))
112 pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ 96 pcm_formats |= SNDRV_PCM_FMTBIT_S24_3BE; /* grrr, big endian!! */
113 else 97 else
114 pcm_format = SNDRV_PCM_FORMAT_S24_3LE; 98 pcm_formats |= SNDRV_PCM_FMTBIT_S24_3LE;
115 break; 99 break;
116 case 4: 100 case 4:
117 pcm_format = SNDRV_PCM_FORMAT_S32_LE; 101 pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE;
118 break; 102 break;
119 default: 103 default:
120 snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", 104 snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
@@ -122,30 +106,29 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip,
122 sample_width, sample_bytes); 106 sample_width, sample_bytes);
123 break; 107 break;
124 } 108 }
125 break; 109 }
126 case UAC_FORMAT_TYPE_I_PCM8: 110 if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) {
127 pcm_format = SNDRV_PCM_FORMAT_U8;
128
129 /* Dallas DS4201 workaround: it advertises U8 format, but really 111 /* Dallas DS4201 workaround: it advertises U8 format, but really
130 supports S8. */ 112 supports S8. */
131 if (chip->usb_id == USB_ID(0x04fa, 0x4201)) 113 if (chip->usb_id == USB_ID(0x04fa, 0x4201))
132 pcm_format = SNDRV_PCM_FORMAT_S8; 114 pcm_formats |= SNDRV_PCM_FMTBIT_S8;
133 break; 115 else
134 case UAC_FORMAT_TYPE_I_IEEE_FLOAT: 116 pcm_formats |= SNDRV_PCM_FMTBIT_U8;
135 pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; 117 }
136 break; 118 if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) {
137 case UAC_FORMAT_TYPE_I_ALAW: 119 pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
138 pcm_format = SNDRV_PCM_FORMAT_A_LAW; 120 }
139 break; 121 if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) {
140 case UAC_FORMAT_TYPE_I_MULAW: 122 pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW;
141 pcm_format = SNDRV_PCM_FORMAT_MU_LAW; 123 }
142 break; 124 if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) {
143 default: 125 pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
144 snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", 126 }
127 if (format & ~0x3f) {
128 snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
145 chip->dev->devnum, fp->iface, fp->altsetting, format); 129 chip->dev->devnum, fp->iface, fp->altsetting, format);
146 break;
147 } 130 }
148 return pcm_format; 131 return pcm_formats;
149} 132}
150 133
151 134
@@ -317,14 +300,14 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
317 default: 300 default:
318 pcm_format = SNDRV_PCM_FORMAT_S16_LE; 301 pcm_format = SNDRV_PCM_FORMAT_S16_LE;
319 } 302 }
303 fp->formats = 1uLL << pcm_format;
320 } else { 304 } else {
321 pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol); 305 fp->formats = parse_audio_format_i_type(chip, fp, format,
322 if (pcm_format < 0) 306 fmt, protocol);
307 if (!fp->formats)
323 return -1; 308 return -1;
324 } 309 }
325 310
326 fp->formats = 1uLL << pcm_format;
327
328 /* gather possible sample rates */ 311 /* gather possible sample rates */
329 /* audio class v1 reports possible sample rates as part of the 312 /* audio class v1 reports possible sample rates as part of the
330 * proprietary class specific descriptor. 313 * proprietary class specific descriptor.