aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/endpoint.c
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-03-04 13:46:13 -0500
committerTakashi Iwai <tiwai@suse.de>2010-03-05 02:17:14 -0500
commite5779998bf8b70e48a6cc208c8b61b33bd6117ea (patch)
tree512568f0fc4b81eac8019522c10df5b81483bcca /sound/usb/endpoint.c
parent3e1aebef6fb55e35668d2d7cf608cf03f30c904f (diff)
ALSA: usb-audio: refactor code
Clean up the usb audio driver by factoring out a lot of functions to separate files. Code for procfs, quirks, urbs, format parsers etc all got a new home now. Moved almost all special quirk handling to quirks.c and introduced new generic functions to handle them, so the exceptions do not pollute the whole driver. Renamed usbaudio.c to card.c because this is what it actually does now. Renamed usbmidi.c to midi.c for namespace clarity. Removed more things from usbaudio.h. The non-standard drivers were adopted accordingly. Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/endpoint.c')
-rw-r--r--sound/usb/endpoint.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
new file mode 100644
index 00000000000..3f53dee1270
--- /dev/null
+++ b/sound/usb/endpoint.c
@@ -0,0 +1,358 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 */
17
18#include <linux/init.h>
19#include <linux/usb.h>
20#include <linux/usb/audio.h>
21
22#include <sound/core.h>
23#include <sound/pcm.h>
24
25#include "usbaudio.h"
26#include "card.h"
27#include "proc.h"
28#include "quirks.h"
29#include "endpoint.h"
30#include "urb.h"
31#include "pcm.h"
32#include "helper.h"
33#include "format.h"
34
35/*
36 * free a substream
37 */
38static void free_substream(struct snd_usb_substream *subs)
39{
40 struct list_head *p, *n;
41
42 if (!subs->num_formats)
43 return; /* not initialized */
44 list_for_each_safe(p, n, &subs->fmt_list) {
45 struct audioformat *fp = list_entry(p, struct audioformat, list);
46 kfree(fp->rate_table);
47 kfree(fp);
48 }
49 kfree(subs->rate_list.list);
50}
51
52
53/*
54 * free a usb stream instance
55 */
56static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
57{
58 free_substream(&stream->substream[0]);
59 free_substream(&stream->substream[1]);
60 list_del(&stream->list);
61 kfree(stream);
62}
63
64static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
65{
66 struct snd_usb_stream *stream = pcm->private_data;
67 if (stream) {
68 stream->pcm = NULL;
69 snd_usb_audio_stream_free(stream);
70 }
71}
72
73
74/*
75 * add this endpoint to the chip instance.
76 * if a stream with the same endpoint already exists, append to it.
77 * if not, create a new pcm stream.
78 */
79int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp)
80{
81 struct list_head *p;
82 struct snd_usb_stream *as;
83 struct snd_usb_substream *subs;
84 struct snd_pcm *pcm;
85 int err;
86
87 list_for_each(p, &chip->pcm_list) {
88 as = list_entry(p, struct snd_usb_stream, list);
89 if (as->fmt_type != fp->fmt_type)
90 continue;
91 subs = &as->substream[stream];
92 if (!subs->endpoint)
93 continue;
94 if (subs->endpoint == fp->endpoint) {
95 list_add_tail(&fp->list, &subs->fmt_list);
96 subs->num_formats++;
97 subs->formats |= 1ULL << fp->format;
98 return 0;
99 }
100 }
101 /* look for an empty stream */
102 list_for_each(p, &chip->pcm_list) {
103 as = list_entry(p, struct snd_usb_stream, list);
104 if (as->fmt_type != fp->fmt_type)
105 continue;
106 subs = &as->substream[stream];
107 if (subs->endpoint)
108 continue;
109 err = snd_pcm_new_stream(as->pcm, stream, 1);
110 if (err < 0)
111 return err;
112 snd_usb_init_substream(as, stream, fp);
113 return 0;
114 }
115
116 /* create a new pcm */
117 as = kzalloc(sizeof(*as), GFP_KERNEL);
118 if (!as)
119 return -ENOMEM;
120 as->pcm_index = chip->pcm_devs;
121 as->chip = chip;
122 as->fmt_type = fp->fmt_type;
123 err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
124 stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
125 stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
126 &pcm);
127 if (err < 0) {
128 kfree(as);
129 return err;
130 }
131 as->pcm = pcm;
132 pcm->private_data = as;
133 pcm->private_free = snd_usb_audio_pcm_free;
134 pcm->info_flags = 0;
135 if (chip->pcm_devs > 0)
136 sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
137 else
138 strcpy(pcm->name, "USB Audio");
139
140 snd_usb_init_substream(as, stream, fp);
141
142 list_add(&as->list, &chip->pcm_list);
143 chip->pcm_devs++;
144
145 snd_usb_proc_pcm_format_add(as);
146
147 return 0;
148}
149
150int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
151{
152 struct usb_device *dev;
153 struct usb_interface *iface;
154 struct usb_host_interface *alts;
155 struct usb_interface_descriptor *altsd;
156 int i, altno, err, stream;
157 int format = 0, num_channels = 0;
158 struct audioformat *fp = NULL;
159 unsigned char *fmt, *csep;
160 int num, protocol;
161
162 dev = chip->dev;
163
164 /* parse the interface's altsettings */
165 iface = usb_ifnum_to_if(dev, iface_no);
166
167 num = iface->num_altsetting;
168
169 /*
170 * Dallas DS4201 workaround: It presents 5 altsettings, but the last
171 * one misses syncpipe, and does not produce any sound.
172 */
173 if (chip->usb_id == USB_ID(0x04fa, 0x4201))
174 num = 4;
175
176 for (i = 0; i < num; i++) {
177 alts = &iface->altsetting[i];
178 altsd = get_iface_desc(alts);
179 protocol = altsd->bInterfaceProtocol;
180 /* skip invalid one */
181 if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
182 altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
183 (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
184 altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
185 altsd->bNumEndpoints < 1 ||
186 le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
187 continue;
188 /* must be isochronous */
189 if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
190 USB_ENDPOINT_XFER_ISOC)
191 continue;
192 /* check direction */
193 stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
194 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
195 altno = altsd->bAlternateSetting;
196
197 if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
198 continue;
199
200 /* get audio formats */
201 switch (protocol) {
202 case UAC_VERSION_1: {
203 struct uac_as_header_descriptor_v1 *as =
204 snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
205
206 if (!as) {
207 snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
208 dev->devnum, iface_no, altno);
209 continue;
210 }
211
212 if (as->bLength < sizeof(*as)) {
213 snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
214 dev->devnum, iface_no, altno);
215 continue;
216 }
217
218 format = le16_to_cpu(as->wFormatTag); /* remember the format value */
219 break;
220 }
221
222 case UAC_VERSION_2: {
223 struct uac_as_header_descriptor_v2 *as =
224 snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
225
226 if (!as) {
227 snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
228 dev->devnum, iface_no, altno);
229 continue;
230 }
231
232 if (as->bLength < sizeof(*as)) {
233 snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
234 dev->devnum, iface_no, altno);
235 continue;
236 }
237
238 num_channels = as->bNrChannels;
239 format = le32_to_cpu(as->bmFormats);
240
241 break;
242 }
243
244 default:
245 snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n",
246 dev->devnum, iface_no, altno, protocol);
247 continue;
248 }
249
250 /* get format type */
251 fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
252 if (!fmt) {
253 snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
254 dev->devnum, iface_no, altno);
255 continue;
256 }
257 if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) ||
258 ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) {
259 snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
260 dev->devnum, iface_no, altno);
261 continue;
262 }
263
264 /*
265 * Blue Microphones workaround: The last altsetting is identical
266 * with the previous one, except for a larger packet size, but
267 * is actually a mislabeled two-channel setting; ignore it.
268 */
269 if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
270 fp && fp->altsetting == 1 && fp->channels == 1 &&
271 fp->format == SNDRV_PCM_FORMAT_S16_LE &&
272 protocol == UAC_VERSION_1 &&
273 le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
274 fp->maxpacksize * 2)
275 continue;
276
277 csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
278 /* Creamware Noah has this descriptor after the 2nd endpoint */
279 if (!csep && altsd->bNumEndpoints >= 2)
280 csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
281 if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) {
282 snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
283 " class specific endpoint descriptor\n",
284 dev->devnum, iface_no, altno);
285 csep = NULL;
286 }
287
288 fp = kzalloc(sizeof(*fp), GFP_KERNEL);
289 if (! fp) {
290 snd_printk(KERN_ERR "cannot malloc\n");
291 return -ENOMEM;
292 }
293
294 fp->iface = iface_no;
295 fp->altsetting = altno;
296 fp->altset_idx = i;
297 fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
298 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
299 fp->datainterval = snd_usb_parse_datainterval(chip, alts);
300 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
301 /* num_channels is only set for v2 interfaces */
302 fp->channels = num_channels;
303 if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
304 fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
305 * (fp->maxpacksize & 0x7ff);
306 fp->attributes = csep ? csep[3] : 0;
307
308 /* some quirks for attributes here */
309
310 switch (chip->usb_id) {
311 case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
312 /* Optoplay sets the sample rate attribute although
313 * it seems not supporting it in fact.
314 */
315 fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
316 break;
317 case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
318 case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
319 /* doesn't set the sample rate attribute, but supports it */
320 fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
321 break;
322 case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
323 case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
324 an older model 77d:223) */
325 /*
326 * plantronics headset and Griffin iMic have set adaptive-in
327 * although it's really not...
328 */
329 fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
330 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
331 fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
332 else
333 fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
334 break;
335 }
336
337 /* ok, let's parse further... */
338 if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
339 kfree(fp->rate_table);
340 kfree(fp);
341 continue;
342 }
343
344 snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
345 err = snd_usb_add_audio_endpoint(chip, stream, fp);
346 if (err < 0) {
347 kfree(fp->rate_table);
348 kfree(fp);
349 return err;
350 }
351 /* try to set the interface... */
352 usb_set_interface(chip->dev, iface_no, altno);
353 snd_usb_init_pitch(chip->dev, iface_no, alts, fp);
354 snd_usb_init_sample_rate(chip->dev, iface_no, alts, fp, fp->rate_max);
355 }
356 return 0;
357}
358