Commit 29088fef3e3f62147c1dd53d764da4f04bf3188d

Authored by Clemens Ladisch
Committed by Takashi Iwai
1 parent 015eb0b081

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>

Showing 2 changed files with 39 additions and 56 deletions Side-by-side Diff

... ... @@ -37,19 +37,20 @@
37 37 * @format: the format tag (wFormatTag)
38 38 * @fmt: the format type descriptor
39 39 */
40   -static int parse_audio_format_i_type(struct snd_usb_audio *chip,
  40 +static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
41 41 struct audioformat *fp,
42 42 int format, void *_fmt,
43 43 int protocol)
44 44 {
45   - int pcm_format, i;
46 45 int sample_width, sample_bytes;
  46 + u64 pcm_formats;
47 47  
48 48 switch (protocol) {
49 49 case UAC_VERSION_1: {
50 50 struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
51 51 sample_width = fmt->bBitResolution;
52 52 sample_bytes = fmt->bSubframeSize;
  53 + format = 1 << format;
53 54 break;
54 55 }
55 56  
... ... @@ -57,24 +58,7 @@
57 58 struct uac_format_type_i_ext_descriptor *fmt = _fmt;
58 59 sample_width = fmt->bBitResolution;
59 60 sample_bytes = fmt->bSubslotSize;
60   -
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   -
  61 + format <<= 1;
78 62 break;
79 63 }
80 64  
81 65  
82 66  
... ... @@ -82,15 +66,15 @@
82 66 return -EINVAL;
83 67 }
84 68  
85   - /* FIXME: correct endianess and sign? */
86   - pcm_format = -1;
  69 + pcm_formats = 0;
87 70  
88   - switch (format) {
89   - case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */
  71 + if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) {
  72 + /* some devices don't define this correctly... */
90 73 snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
91 74 chip->dev->devnum, fp->iface, fp->altsetting);
92   - /* fall-through */
93   - case UAC_FORMAT_TYPE_I_PCM:
  75 + format = 1 << UAC_FORMAT_TYPE_I_PCM;
  76 + }
  77 + if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
94 78 if (sample_width > sample_bytes * 8) {
95 79 snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
96 80 chip->dev->devnum, fp->iface, fp->altsetting,
97 81  
98 82  
99 83  
100 84  
101 85  
... ... @@ -99,22 +83,22 @@
99 83 /* check the format byte size */
100 84 switch (sample_bytes) {
101 85 case 1:
102   - pcm_format = SNDRV_PCM_FORMAT_S8;
  86 + pcm_formats |= SNDRV_PCM_FMTBIT_S8;
103 87 break;
104 88 case 2:
105 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 91 else
108   - pcm_format = SNDRV_PCM_FORMAT_S16_LE;
  92 + pcm_formats |= SNDRV_PCM_FMTBIT_S16_LE;
109 93 break;
110 94 case 3:
111 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 97 else
114   - pcm_format = SNDRV_PCM_FORMAT_S24_3LE;
  98 + pcm_formats |= SNDRV_PCM_FMTBIT_S24_3LE;
115 99 break;
116 100 case 4:
117   - pcm_format = SNDRV_PCM_FORMAT_S32_LE;
  101 + pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE;
118 102 break;
119 103 default:
120 104 snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
121 105  
122 106  
123 107  
... ... @@ -122,30 +106,29 @@
122 106 sample_width, sample_bytes);
123 107 break;
124 108 }
125   - break;
126   - case UAC_FORMAT_TYPE_I_PCM8:
127   - pcm_format = SNDRV_PCM_FORMAT_U8;
128   -
  109 + }
  110 + if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) {
129 111 /* Dallas DS4201 workaround: it advertises U8 format, but really
130 112 supports S8. */
131 113 if (chip->usb_id == USB_ID(0x04fa, 0x4201))
132   - pcm_format = SNDRV_PCM_FORMAT_S8;
133   - break;
134   - case UAC_FORMAT_TYPE_I_IEEE_FLOAT:
135   - pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
136   - break;
137   - case UAC_FORMAT_TYPE_I_ALAW:
138   - pcm_format = SNDRV_PCM_FORMAT_A_LAW;
139   - break;
140   - case UAC_FORMAT_TYPE_I_MULAW:
141   - pcm_format = SNDRV_PCM_FORMAT_MU_LAW;
142   - break;
143   - default:
144   - snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n",
  114 + pcm_formats |= SNDRV_PCM_FMTBIT_S8;
  115 + else
  116 + pcm_formats |= SNDRV_PCM_FMTBIT_U8;
  117 + }
  118 + if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) {
  119 + pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
  120 + }
  121 + if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) {
  122 + pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW;
  123 + }
  124 + if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) {
  125 + pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
  126 + }
  127 + if (format & ~0x3f) {
  128 + snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
145 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  
152 135  
153 136  
... ... @@ -317,13 +300,13 @@
317 300 default:
318 301 pcm_format = SNDRV_PCM_FORMAT_S16_LE;
319 302 }
  303 + fp->formats = 1uLL << pcm_format;
320 304 } else {
321   - pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol);
322   - if (pcm_format < 0)
  305 + fp->formats = parse_audio_format_i_type(chip, fp, format,
  306 + fmt, protocol);
  307 + if (!fp->formats)
323 308 return -1;
324 309 }
325   -
326   - fp->formats = 1uLL << pcm_format;
327 310  
328 311 /* gather possible sample rates */
329 312 /* audio class v1 reports possible sample rates as part of the
sound/usb/quirks-table.h
... ... @@ -2203,7 +2203,7 @@
2203 2203 .ifnum = 1,
2204 2204 .type = QUIRK_AUDIO_FIXED_ENDPOINT,
2205 2205 .data = &(const struct audioformat) {
2206   - .format = SNDRV_PCM_FORMAT_S24_3BE,
  2206 + .formats = SNDRV_PCM_FMTBIT_S24_3BE,
2207 2207 .channels = 2,
2208 2208 .iface = 1,
2209 2209 .altsetting = 1,