diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2010-03-04 13:46:16 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-03-05 02:18:54 -0500 |
commit | 29088fef3e3f62147c1dd53d764da4f04bf3188d (patch) | |
tree | b8da9e5171427315a9d50be8fa5a2537f651c5c1 /sound/usb/format.c | |
parent | 015eb0b08150c6fef843efe22609589ead3d4fb8 (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.c | 93 |
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 | */ |
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 | 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. |