diff options
-rw-r--r-- | sound/usb/Makefile | 1 | ||||
-rw-r--r-- | sound/usb/card.c | 3 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 433 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 7 | ||||
-rw-r--r-- | sound/usb/quirks.c | 7 | ||||
-rw-r--r-- | sound/usb/stream.c | 453 | ||||
-rw-r--r-- | sound/usb/stream.h | 12 |
7 files changed, 472 insertions, 444 deletions
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 083501e78f34..5390db00e098 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
@@ -12,6 +12,7 @@ snd-usb-audio-objs := card.o \ | |||
12 | pcm.o \ | 12 | pcm.o \ |
13 | proc.o \ | 13 | proc.o \ |
14 | quirks.o \ | 14 | quirks.o \ |
15 | stream.o \ | ||
15 | urb.o | 16 | urb.o |
16 | 17 | ||
17 | snd-usbmidi-lib-objs := midi.o | 18 | snd-usbmidi-lib-objs := midi.o |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 781d9e61adfb..a3136afb2198 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -68,6 +68,7 @@ | |||
68 | #include "urb.h" | 68 | #include "urb.h" |
69 | #include "format.h" | 69 | #include "format.h" |
70 | #include "power.h" | 70 | #include "power.h" |
71 | #include "stream.h" | ||
71 | 72 | ||
72 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 73 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
73 | MODULE_DESCRIPTION("USB Audio"); | 74 | MODULE_DESCRIPTION("USB Audio"); |
@@ -185,7 +186,7 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int | |||
185 | return -EINVAL; | 186 | return -EINVAL; |
186 | } | 187 | } |
187 | 188 | ||
188 | if (! snd_usb_parse_audio_endpoints(chip, interface)) { | 189 | if (! snd_usb_parse_audio_interface(chip, interface)) { |
189 | usb_set_interface(dev, interface, 0); /* reset the current interface */ | 190 | usb_set_interface(dev, interface, 0); /* reset the current interface */ |
190 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | 191 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); |
191 | return -EINVAL; | 192 | return -EINVAL; |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7d46e482375d..b3ee7cf243df 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -15,436 +15,3 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/usb.h> | ||
21 | #include <linux/usb/audio.h> | ||
22 | #include <linux/usb/audio-v2.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | |||
27 | #include "usbaudio.h" | ||
28 | #include "card.h" | ||
29 | #include "proc.h" | ||
30 | #include "quirks.h" | ||
31 | #include "endpoint.h" | ||
32 | #include "urb.h" | ||
33 | #include "pcm.h" | ||
34 | #include "helper.h" | ||
35 | #include "format.h" | ||
36 | #include "clock.h" | ||
37 | |||
38 | /* | ||
39 | * free a substream | ||
40 | */ | ||
41 | static void free_substream(struct snd_usb_substream *subs) | ||
42 | { | ||
43 | struct list_head *p, *n; | ||
44 | |||
45 | if (!subs->num_formats) | ||
46 | return; /* not initialized */ | ||
47 | list_for_each_safe(p, n, &subs->fmt_list) { | ||
48 | struct audioformat *fp = list_entry(p, struct audioformat, list); | ||
49 | kfree(fp->rate_table); | ||
50 | kfree(fp); | ||
51 | } | ||
52 | kfree(subs->rate_list.list); | ||
53 | } | ||
54 | |||
55 | |||
56 | /* | ||
57 | * free a usb stream instance | ||
58 | */ | ||
59 | static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) | ||
60 | { | ||
61 | free_substream(&stream->substream[0]); | ||
62 | free_substream(&stream->substream[1]); | ||
63 | list_del(&stream->list); | ||
64 | kfree(stream); | ||
65 | } | ||
66 | |||
67 | static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) | ||
68 | { | ||
69 | struct snd_usb_stream *stream = pcm->private_data; | ||
70 | if (stream) { | ||
71 | stream->pcm = NULL; | ||
72 | snd_usb_audio_stream_free(stream); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | |||
77 | /* | ||
78 | * add this endpoint to the chip instance. | ||
79 | * if a stream with the same endpoint already exists, append to it. | ||
80 | * if not, create a new pcm stream. | ||
81 | */ | ||
82 | int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) | ||
83 | { | ||
84 | struct list_head *p; | ||
85 | struct snd_usb_stream *as; | ||
86 | struct snd_usb_substream *subs; | ||
87 | struct snd_pcm *pcm; | ||
88 | int err; | ||
89 | |||
90 | list_for_each(p, &chip->pcm_list) { | ||
91 | as = list_entry(p, struct snd_usb_stream, list); | ||
92 | if (as->fmt_type != fp->fmt_type) | ||
93 | continue; | ||
94 | subs = &as->substream[stream]; | ||
95 | if (!subs->endpoint) | ||
96 | continue; | ||
97 | if (subs->endpoint == fp->endpoint) { | ||
98 | list_add_tail(&fp->list, &subs->fmt_list); | ||
99 | subs->num_formats++; | ||
100 | subs->formats |= fp->formats; | ||
101 | return 0; | ||
102 | } | ||
103 | } | ||
104 | /* look for an empty stream */ | ||
105 | list_for_each(p, &chip->pcm_list) { | ||
106 | as = list_entry(p, struct snd_usb_stream, list); | ||
107 | if (as->fmt_type != fp->fmt_type) | ||
108 | continue; | ||
109 | subs = &as->substream[stream]; | ||
110 | if (subs->endpoint) | ||
111 | continue; | ||
112 | err = snd_pcm_new_stream(as->pcm, stream, 1); | ||
113 | if (err < 0) | ||
114 | return err; | ||
115 | snd_usb_init_substream(as, stream, fp); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* create a new pcm */ | ||
120 | as = kzalloc(sizeof(*as), GFP_KERNEL); | ||
121 | if (!as) | ||
122 | return -ENOMEM; | ||
123 | as->pcm_index = chip->pcm_devs; | ||
124 | as->chip = chip; | ||
125 | as->fmt_type = fp->fmt_type; | ||
126 | err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, | ||
127 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, | ||
128 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, | ||
129 | &pcm); | ||
130 | if (err < 0) { | ||
131 | kfree(as); | ||
132 | return err; | ||
133 | } | ||
134 | as->pcm = pcm; | ||
135 | pcm->private_data = as; | ||
136 | pcm->private_free = snd_usb_audio_pcm_free; | ||
137 | pcm->info_flags = 0; | ||
138 | if (chip->pcm_devs > 0) | ||
139 | sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); | ||
140 | else | ||
141 | strcpy(pcm->name, "USB Audio"); | ||
142 | |||
143 | snd_usb_init_substream(as, stream, fp); | ||
144 | |||
145 | list_add(&as->list, &chip->pcm_list); | ||
146 | chip->pcm_devs++; | ||
147 | |||
148 | snd_usb_proc_pcm_format_add(as); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, | ||
154 | struct usb_host_interface *alts, | ||
155 | int protocol, int iface_no) | ||
156 | { | ||
157 | /* parsed with a v1 header here. that's ok as we only look at the | ||
158 | * header first which is the same for both versions */ | ||
159 | struct uac_iso_endpoint_descriptor *csep; | ||
160 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
161 | int attributes = 0; | ||
162 | |||
163 | csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); | ||
164 | |||
165 | /* Creamware Noah has this descriptor after the 2nd endpoint */ | ||
166 | if (!csep && altsd->bNumEndpoints >= 2) | ||
167 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); | ||
168 | |||
169 | if (!csep || csep->bLength < 7 || | ||
170 | csep->bDescriptorSubtype != UAC_EP_GENERAL) { | ||
171 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" | ||
172 | " class specific endpoint descriptor\n", | ||
173 | chip->dev->devnum, iface_no, | ||
174 | altsd->bAlternateSetting); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | if (protocol == UAC_VERSION_1) { | ||
179 | attributes = csep->bmAttributes; | ||
180 | } else { | ||
181 | struct uac2_iso_endpoint_descriptor *csep2 = | ||
182 | (struct uac2_iso_endpoint_descriptor *) csep; | ||
183 | |||
184 | attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; | ||
185 | |||
186 | /* emulate the endpoint attributes of a v1 device */ | ||
187 | if (csep2->bmControls & UAC2_CONTROL_PITCH) | ||
188 | attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; | ||
189 | } | ||
190 | |||
191 | return attributes; | ||
192 | } | ||
193 | |||
194 | static struct uac2_input_terminal_descriptor * | ||
195 | snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
196 | int terminal_id) | ||
197 | { | ||
198 | struct uac2_input_terminal_descriptor *term = NULL; | ||
199 | |||
200 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
201 | ctrl_iface->extralen, | ||
202 | term, UAC_INPUT_TERMINAL))) { | ||
203 | if (term->bTerminalID == terminal_id) | ||
204 | return term; | ||
205 | } | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | static struct uac2_output_terminal_descriptor * | ||
211 | snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
212 | int terminal_id) | ||
213 | { | ||
214 | struct uac2_output_terminal_descriptor *term = NULL; | ||
215 | |||
216 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
217 | ctrl_iface->extralen, | ||
218 | term, UAC_OUTPUT_TERMINAL))) { | ||
219 | if (term->bTerminalID == terminal_id) | ||
220 | return term; | ||
221 | } | ||
222 | |||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | ||
227 | { | ||
228 | struct usb_device *dev; | ||
229 | struct usb_interface *iface; | ||
230 | struct usb_host_interface *alts; | ||
231 | struct usb_interface_descriptor *altsd; | ||
232 | int i, altno, err, stream; | ||
233 | int format = 0, num_channels = 0; | ||
234 | struct audioformat *fp = NULL; | ||
235 | int num, protocol, clock = 0; | ||
236 | struct uac_format_type_i_continuous_descriptor *fmt; | ||
237 | |||
238 | dev = chip->dev; | ||
239 | |||
240 | /* parse the interface's altsettings */ | ||
241 | iface = usb_ifnum_to_if(dev, iface_no); | ||
242 | |||
243 | num = iface->num_altsetting; | ||
244 | |||
245 | /* | ||
246 | * Dallas DS4201 workaround: It presents 5 altsettings, but the last | ||
247 | * one misses syncpipe, and does not produce any sound. | ||
248 | */ | ||
249 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) | ||
250 | num = 4; | ||
251 | |||
252 | for (i = 0; i < num; i++) { | ||
253 | alts = &iface->altsetting[i]; | ||
254 | altsd = get_iface_desc(alts); | ||
255 | protocol = altsd->bInterfaceProtocol; | ||
256 | /* skip invalid one */ | ||
257 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | ||
258 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | ||
259 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && | ||
260 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || | ||
261 | altsd->bNumEndpoints < 1 || | ||
262 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) | ||
263 | continue; | ||
264 | /* must be isochronous */ | ||
265 | if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != | ||
266 | USB_ENDPOINT_XFER_ISOC) | ||
267 | continue; | ||
268 | /* check direction */ | ||
269 | stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? | ||
270 | SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | ||
271 | altno = altsd->bAlternateSetting; | ||
272 | |||
273 | if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) | ||
274 | continue; | ||
275 | |||
276 | /* get audio formats */ | ||
277 | switch (protocol) { | ||
278 | default: | ||
279 | snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", | ||
280 | dev->devnum, iface_no, altno, protocol); | ||
281 | protocol = UAC_VERSION_1; | ||
282 | /* fall through */ | ||
283 | |||
284 | case UAC_VERSION_1: { | ||
285 | struct uac1_as_header_descriptor *as = | ||
286 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
287 | |||
288 | if (!as) { | ||
289 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
290 | dev->devnum, iface_no, altno); | ||
291 | continue; | ||
292 | } | ||
293 | |||
294 | if (as->bLength < sizeof(*as)) { | ||
295 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
296 | dev->devnum, iface_no, altno); | ||
297 | continue; | ||
298 | } | ||
299 | |||
300 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | case UAC_VERSION_2: { | ||
305 | struct uac2_input_terminal_descriptor *input_term; | ||
306 | struct uac2_output_terminal_descriptor *output_term; | ||
307 | struct uac2_as_header_descriptor *as = | ||
308 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
309 | |||
310 | if (!as) { | ||
311 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
312 | dev->devnum, iface_no, altno); | ||
313 | continue; | ||
314 | } | ||
315 | |||
316 | if (as->bLength < sizeof(*as)) { | ||
317 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
318 | dev->devnum, iface_no, altno); | ||
319 | continue; | ||
320 | } | ||
321 | |||
322 | num_channels = as->bNrChannels; | ||
323 | format = le32_to_cpu(as->bmFormats); | ||
324 | |||
325 | /* lookup the terminal associated to this interface | ||
326 | * to extract the clock */ | ||
327 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
328 | as->bTerminalLink); | ||
329 | if (input_term) { | ||
330 | clock = input_term->bCSourceID; | ||
331 | break; | ||
332 | } | ||
333 | |||
334 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
335 | as->bTerminalLink); | ||
336 | if (output_term) { | ||
337 | clock = output_term->bCSourceID; | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", | ||
342 | dev->devnum, iface_no, altno, as->bTerminalLink); | ||
343 | continue; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /* get format type */ | ||
348 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); | ||
349 | if (!fmt) { | ||
350 | snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", | ||
351 | dev->devnum, iface_no, altno); | ||
352 | continue; | ||
353 | } | ||
354 | if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || | ||
355 | ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) { | ||
356 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
357 | dev->devnum, iface_no, altno); | ||
358 | continue; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * Blue Microphones workaround: The last altsetting is identical | ||
363 | * with the previous one, except for a larger packet size, but | ||
364 | * is actually a mislabeled two-channel setting; ignore it. | ||
365 | */ | ||
366 | if (fmt->bNrChannels == 1 && | ||
367 | fmt->bSubframeSize == 2 && | ||
368 | altno == 2 && num == 3 && | ||
369 | fp && fp->altsetting == 1 && fp->channels == 1 && | ||
370 | fp->formats == SNDRV_PCM_FMTBIT_S16_LE && | ||
371 | protocol == UAC_VERSION_1 && | ||
372 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == | ||
373 | fp->maxpacksize * 2) | ||
374 | continue; | ||
375 | |||
376 | fp = kzalloc(sizeof(*fp), GFP_KERNEL); | ||
377 | if (! fp) { | ||
378 | snd_printk(KERN_ERR "cannot malloc\n"); | ||
379 | return -ENOMEM; | ||
380 | } | ||
381 | |||
382 | fp->iface = iface_no; | ||
383 | fp->altsetting = altno; | ||
384 | fp->altset_idx = i; | ||
385 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
386 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
387 | fp->datainterval = snd_usb_parse_datainterval(chip, alts); | ||
388 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
389 | /* num_channels is only set for v2 interfaces */ | ||
390 | fp->channels = num_channels; | ||
391 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | ||
392 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | ||
393 | * (fp->maxpacksize & 0x7ff); | ||
394 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | ||
395 | fp->clock = clock; | ||
396 | |||
397 | /* some quirks for attributes here */ | ||
398 | |||
399 | switch (chip->usb_id) { | ||
400 | case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ | ||
401 | /* Optoplay sets the sample rate attribute although | ||
402 | * it seems not supporting it in fact. | ||
403 | */ | ||
404 | fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; | ||
405 | break; | ||
406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | ||
407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | ||
408 | /* doesn't set the sample rate attribute, but supports it */ | ||
409 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; | ||
410 | break; | ||
411 | case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ | ||
412 | case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ | ||
413 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ | ||
414 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is | ||
415 | an older model 77d:223) */ | ||
416 | /* | ||
417 | * plantronics headset and Griffin iMic have set adaptive-in | ||
418 | * although it's really not... | ||
419 | */ | ||
420 | fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; | ||
421 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
422 | fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; | ||
423 | else | ||
424 | fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; | ||
425 | break; | ||
426 | } | ||
427 | |||
428 | /* ok, let's parse further... */ | ||
429 | if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { | ||
430 | kfree(fp->rate_table); | ||
431 | kfree(fp); | ||
432 | fp = NULL; | ||
433 | continue; | ||
434 | } | ||
435 | |||
436 | snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); | ||
437 | err = snd_usb_add_audio_endpoint(chip, stream, fp); | ||
438 | if (err < 0) { | ||
439 | kfree(fp->rate_table); | ||
440 | kfree(fp); | ||
441 | return err; | ||
442 | } | ||
443 | /* try to set the interface... */ | ||
444 | usb_set_interface(chip->dev, iface_no, altno); | ||
445 | snd_usb_init_pitch(chip, iface_no, alts, fp); | ||
446 | snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); | ||
447 | } | ||
448 | return 0; | ||
449 | } | ||
450 | |||
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 64dd0db023b2..e5d8a6adf38f 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h | |||
@@ -1,11 +1,4 @@ | |||
1 | #ifndef __USBAUDIO_ENDPOINT_H | 1 | #ifndef __USBAUDIO_ENDPOINT_H |
2 | #define __USBAUDIO_ENDPOINT_H | 2 | #define __USBAUDIO_ENDPOINT_H |
3 | 3 | ||
4 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, | ||
5 | int iface_no); | ||
6 | |||
7 | int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, | ||
8 | int stream, | ||
9 | struct audioformat *fp); | ||
10 | |||
11 | #endif /* __USBAUDIO_ENDPOINT_H */ | 4 | #endif /* __USBAUDIO_ENDPOINT_H */ |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index cf61b0340026..556edea28b90 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "endpoint.h" | 34 | #include "endpoint.h" |
35 | #include "pcm.h" | 35 | #include "pcm.h" |
36 | #include "clock.h" | 36 | #include "clock.h" |
37 | #include "stream.h" | ||
37 | 38 | ||
38 | /* | 39 | /* |
39 | * handle the quirks for the contained interfaces | 40 | * handle the quirks for the contained interfaces |
@@ -106,7 +107,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip, | |||
106 | 107 | ||
107 | alts = &iface->altsetting[0]; | 108 | alts = &iface->altsetting[0]; |
108 | altsd = get_iface_desc(alts); | 109 | altsd = get_iface_desc(alts); |
109 | err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber); | 110 | err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber); |
110 | if (err < 0) { | 111 | if (err < 0) { |
111 | snd_printk(KERN_ERR "cannot setup if %d: error %d\n", | 112 | snd_printk(KERN_ERR "cannot setup if %d: error %d\n", |
112 | altsd->bInterfaceNumber, err); | 113 | altsd->bInterfaceNumber, err); |
@@ -147,7 +148,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, | |||
147 | 148 | ||
148 | stream = (fp->endpoint & USB_DIR_IN) | 149 | stream = (fp->endpoint & USB_DIR_IN) |
149 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | 150 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
150 | err = snd_usb_add_audio_endpoint(chip, stream, fp); | 151 | err = snd_usb_add_audio_stream(chip, stream, fp); |
151 | if (err < 0) { | 152 | if (err < 0) { |
152 | kfree(fp); | 153 | kfree(fp); |
153 | kfree(rate_table); | 154 | kfree(rate_table); |
@@ -254,7 +255,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
254 | 255 | ||
255 | stream = (fp->endpoint & USB_DIR_IN) | 256 | stream = (fp->endpoint & USB_DIR_IN) |
256 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | 257 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
257 | err = snd_usb_add_audio_endpoint(chip, stream, fp); | 258 | err = snd_usb_add_audio_stream(chip, stream, fp); |
258 | if (err < 0) { | 259 | if (err < 0) { |
259 | kfree(fp); | 260 | kfree(fp); |
260 | return err; | 261 | return err; |
diff --git a/sound/usb/stream.c b/sound/usb/stream.c new file mode 100644 index 000000000000..4688d4c6208b --- /dev/null +++ b/sound/usb/stream.c | |||
@@ -0,0 +1,453 @@ | |||
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/slab.h> | ||
20 | #include <linux/usb.h> | ||
21 | #include <linux/usb/audio.h> | ||
22 | #include <linux/usb/audio-v2.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | |||
27 | #include "usbaudio.h" | ||
28 | #include "card.h" | ||
29 | #include "proc.h" | ||
30 | #include "quirks.h" | ||
31 | #include "endpoint.h" | ||
32 | #include "urb.h" | ||
33 | #include "pcm.h" | ||
34 | #include "helper.h" | ||
35 | #include "format.h" | ||
36 | #include "clock.h" | ||
37 | #include "stream.h" | ||
38 | |||
39 | /* | ||
40 | * free a substream | ||
41 | */ | ||
42 | static void free_substream(struct snd_usb_substream *subs) | ||
43 | { | ||
44 | struct list_head *p, *n; | ||
45 | |||
46 | if (!subs->num_formats) | ||
47 | return; /* not initialized */ | ||
48 | list_for_each_safe(p, n, &subs->fmt_list) { | ||
49 | struct audioformat *fp = list_entry(p, struct audioformat, list); | ||
50 | kfree(fp->rate_table); | ||
51 | kfree(fp); | ||
52 | } | ||
53 | kfree(subs->rate_list.list); | ||
54 | } | ||
55 | |||
56 | |||
57 | /* | ||
58 | * free a usb stream instance | ||
59 | */ | ||
60 | static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) | ||
61 | { | ||
62 | free_substream(&stream->substream[0]); | ||
63 | free_substream(&stream->substream[1]); | ||
64 | list_del(&stream->list); | ||
65 | kfree(stream); | ||
66 | } | ||
67 | |||
68 | static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) | ||
69 | { | ||
70 | struct snd_usb_stream *stream = pcm->private_data; | ||
71 | if (stream) { | ||
72 | stream->pcm = NULL; | ||
73 | snd_usb_audio_stream_free(stream); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | |||
78 | /* | ||
79 | * add this endpoint to the chip instance. | ||
80 | * if a stream with the same endpoint already exists, append to it. | ||
81 | * if not, create a new pcm stream. | ||
82 | */ | ||
83 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | ||
84 | int stream, | ||
85 | struct audioformat *fp) | ||
86 | { | ||
87 | struct list_head *p; | ||
88 | struct snd_usb_stream *as; | ||
89 | struct snd_usb_substream *subs; | ||
90 | struct snd_pcm *pcm; | ||
91 | int err; | ||
92 | |||
93 | list_for_each(p, &chip->pcm_list) { | ||
94 | as = list_entry(p, struct snd_usb_stream, list); | ||
95 | if (as->fmt_type != fp->fmt_type) | ||
96 | continue; | ||
97 | subs = &as->substream[stream]; | ||
98 | if (!subs->endpoint) | ||
99 | continue; | ||
100 | if (subs->endpoint == fp->endpoint) { | ||
101 | list_add_tail(&fp->list, &subs->fmt_list); | ||
102 | subs->num_formats++; | ||
103 | subs->formats |= fp->formats; | ||
104 | return 0; | ||
105 | } | ||
106 | } | ||
107 | /* look for an empty stream */ | ||
108 | list_for_each(p, &chip->pcm_list) { | ||
109 | as = list_entry(p, struct snd_usb_stream, list); | ||
110 | if (as->fmt_type != fp->fmt_type) | ||
111 | continue; | ||
112 | subs = &as->substream[stream]; | ||
113 | if (subs->endpoint) | ||
114 | continue; | ||
115 | err = snd_pcm_new_stream(as->pcm, stream, 1); | ||
116 | if (err < 0) | ||
117 | return err; | ||
118 | snd_usb_init_substream(as, stream, fp); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* create a new pcm */ | ||
123 | as = kzalloc(sizeof(*as), GFP_KERNEL); | ||
124 | if (!as) | ||
125 | return -ENOMEM; | ||
126 | as->pcm_index = chip->pcm_devs; | ||
127 | as->chip = chip; | ||
128 | as->fmt_type = fp->fmt_type; | ||
129 | err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, | ||
130 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, | ||
131 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, | ||
132 | &pcm); | ||
133 | if (err < 0) { | ||
134 | kfree(as); | ||
135 | return err; | ||
136 | } | ||
137 | as->pcm = pcm; | ||
138 | pcm->private_data = as; | ||
139 | pcm->private_free = snd_usb_audio_pcm_free; | ||
140 | pcm->info_flags = 0; | ||
141 | if (chip->pcm_devs > 0) | ||
142 | sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); | ||
143 | else | ||
144 | strcpy(pcm->name, "USB Audio"); | ||
145 | |||
146 | snd_usb_init_substream(as, stream, fp); | ||
147 | |||
148 | list_add(&as->list, &chip->pcm_list); | ||
149 | chip->pcm_devs++; | ||
150 | |||
151 | snd_usb_proc_pcm_format_add(as); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, | ||
157 | struct usb_host_interface *alts, | ||
158 | int protocol, int iface_no) | ||
159 | { | ||
160 | /* parsed with a v1 header here. that's ok as we only look at the | ||
161 | * header first which is the same for both versions */ | ||
162 | struct uac_iso_endpoint_descriptor *csep; | ||
163 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
164 | int attributes = 0; | ||
165 | |||
166 | csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); | ||
167 | |||
168 | /* Creamware Noah has this descriptor after the 2nd endpoint */ | ||
169 | if (!csep && altsd->bNumEndpoints >= 2) | ||
170 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); | ||
171 | |||
172 | if (!csep || csep->bLength < 7 || | ||
173 | csep->bDescriptorSubtype != UAC_EP_GENERAL) { | ||
174 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" | ||
175 | " class specific endpoint descriptor\n", | ||
176 | chip->dev->devnum, iface_no, | ||
177 | altsd->bAlternateSetting); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | if (protocol == UAC_VERSION_1) { | ||
182 | attributes = csep->bmAttributes; | ||
183 | } else { | ||
184 | struct uac2_iso_endpoint_descriptor *csep2 = | ||
185 | (struct uac2_iso_endpoint_descriptor *) csep; | ||
186 | |||
187 | attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; | ||
188 | |||
189 | /* emulate the endpoint attributes of a v1 device */ | ||
190 | if (csep2->bmControls & UAC2_CONTROL_PITCH) | ||
191 | attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; | ||
192 | } | ||
193 | |||
194 | return attributes; | ||
195 | } | ||
196 | |||
197 | static struct uac2_input_terminal_descriptor * | ||
198 | snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
199 | int terminal_id) | ||
200 | { | ||
201 | struct uac2_input_terminal_descriptor *term = NULL; | ||
202 | |||
203 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
204 | ctrl_iface->extralen, | ||
205 | term, UAC_INPUT_TERMINAL))) { | ||
206 | if (term->bTerminalID == terminal_id) | ||
207 | return term; | ||
208 | } | ||
209 | |||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | static struct uac2_output_terminal_descriptor * | ||
214 | snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
215 | int terminal_id) | ||
216 | { | ||
217 | struct uac2_output_terminal_descriptor *term = NULL; | ||
218 | |||
219 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
220 | ctrl_iface->extralen, | ||
221 | term, UAC_OUTPUT_TERMINAL))) { | ||
222 | if (term->bTerminalID == terminal_id) | ||
223 | return term; | ||
224 | } | ||
225 | |||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | ||
230 | { | ||
231 | struct usb_device *dev; | ||
232 | struct usb_interface *iface; | ||
233 | struct usb_host_interface *alts; | ||
234 | struct usb_interface_descriptor *altsd; | ||
235 | int i, altno, err, stream; | ||
236 | int format = 0, num_channels = 0; | ||
237 | struct audioformat *fp = NULL; | ||
238 | int num, protocol, clock = 0; | ||
239 | struct uac_format_type_i_continuous_descriptor *fmt; | ||
240 | |||
241 | dev = chip->dev; | ||
242 | |||
243 | /* parse the interface's altsettings */ | ||
244 | iface = usb_ifnum_to_if(dev, iface_no); | ||
245 | |||
246 | num = iface->num_altsetting; | ||
247 | |||
248 | /* | ||
249 | * Dallas DS4201 workaround: It presents 5 altsettings, but the last | ||
250 | * one misses syncpipe, and does not produce any sound. | ||
251 | */ | ||
252 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) | ||
253 | num = 4; | ||
254 | |||
255 | for (i = 0; i < num; i++) { | ||
256 | alts = &iface->altsetting[i]; | ||
257 | altsd = get_iface_desc(alts); | ||
258 | protocol = altsd->bInterfaceProtocol; | ||
259 | /* skip invalid one */ | ||
260 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | ||
261 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | ||
262 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && | ||
263 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || | ||
264 | altsd->bNumEndpoints < 1 || | ||
265 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) | ||
266 | continue; | ||
267 | /* must be isochronous */ | ||
268 | if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != | ||
269 | USB_ENDPOINT_XFER_ISOC) | ||
270 | continue; | ||
271 | /* check direction */ | ||
272 | stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? | ||
273 | SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | ||
274 | altno = altsd->bAlternateSetting; | ||
275 | |||
276 | if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) | ||
277 | continue; | ||
278 | |||
279 | /* get audio formats */ | ||
280 | switch (protocol) { | ||
281 | default: | ||
282 | snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", | ||
283 | dev->devnum, iface_no, altno, protocol); | ||
284 | protocol = UAC_VERSION_1; | ||
285 | /* fall through */ | ||
286 | |||
287 | case UAC_VERSION_1: { | ||
288 | struct uac1_as_header_descriptor *as = | ||
289 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
290 | |||
291 | if (!as) { | ||
292 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
293 | dev->devnum, iface_no, altno); | ||
294 | continue; | ||
295 | } | ||
296 | |||
297 | if (as->bLength < sizeof(*as)) { | ||
298 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
299 | dev->devnum, iface_no, altno); | ||
300 | continue; | ||
301 | } | ||
302 | |||
303 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | case UAC_VERSION_2: { | ||
308 | struct uac2_input_terminal_descriptor *input_term; | ||
309 | struct uac2_output_terminal_descriptor *output_term; | ||
310 | struct uac2_as_header_descriptor *as = | ||
311 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
312 | |||
313 | if (!as) { | ||
314 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
315 | dev->devnum, iface_no, altno); | ||
316 | continue; | ||
317 | } | ||
318 | |||
319 | if (as->bLength < sizeof(*as)) { | ||
320 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
321 | dev->devnum, iface_no, altno); | ||
322 | continue; | ||
323 | } | ||
324 | |||
325 | num_channels = as->bNrChannels; | ||
326 | format = le32_to_cpu(as->bmFormats); | ||
327 | |||
328 | /* lookup the terminal associated to this interface | ||
329 | * to extract the clock */ | ||
330 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
331 | as->bTerminalLink); | ||
332 | if (input_term) { | ||
333 | clock = input_term->bCSourceID; | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
338 | as->bTerminalLink); | ||
339 | if (output_term) { | ||
340 | clock = output_term->bCSourceID; | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", | ||
345 | dev->devnum, iface_no, altno, as->bTerminalLink); | ||
346 | continue; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* get format type */ | ||
351 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); | ||
352 | if (!fmt) { | ||
353 | snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", | ||
354 | dev->devnum, iface_no, altno); | ||
355 | continue; | ||
356 | } | ||
357 | if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || | ||
358 | ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) { | ||
359 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
360 | dev->devnum, iface_no, altno); | ||
361 | continue; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Blue Microphones workaround: The last altsetting is identical | ||
366 | * with the previous one, except for a larger packet size, but | ||
367 | * is actually a mislabeled two-channel setting; ignore it. | ||
368 | */ | ||
369 | if (fmt->bNrChannels == 1 && | ||
370 | fmt->bSubframeSize == 2 && | ||
371 | altno == 2 && num == 3 && | ||
372 | fp && fp->altsetting == 1 && fp->channels == 1 && | ||
373 | fp->formats == SNDRV_PCM_FMTBIT_S16_LE && | ||
374 | protocol == UAC_VERSION_1 && | ||
375 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == | ||
376 | fp->maxpacksize * 2) | ||
377 | continue; | ||
378 | |||
379 | fp = kzalloc(sizeof(*fp), GFP_KERNEL); | ||
380 | if (! fp) { | ||
381 | snd_printk(KERN_ERR "cannot malloc\n"); | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | |||
385 | fp->iface = iface_no; | ||
386 | fp->altsetting = altno; | ||
387 | fp->altset_idx = i; | ||
388 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
389 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
390 | fp->datainterval = snd_usb_parse_datainterval(chip, alts); | ||
391 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
392 | /* num_channels is only set for v2 interfaces */ | ||
393 | fp->channels = num_channels; | ||
394 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | ||
395 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | ||
396 | * (fp->maxpacksize & 0x7ff); | ||
397 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | ||
398 | fp->clock = clock; | ||
399 | |||
400 | /* some quirks for attributes here */ | ||
401 | |||
402 | switch (chip->usb_id) { | ||
403 | case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ | ||
404 | /* Optoplay sets the sample rate attribute although | ||
405 | * it seems not supporting it in fact. | ||
406 | */ | ||
407 | fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; | ||
408 | break; | ||
409 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | ||
410 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | ||
411 | /* doesn't set the sample rate attribute, but supports it */ | ||
412 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; | ||
413 | break; | ||
414 | case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ | ||
415 | case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ | ||
416 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ | ||
417 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is | ||
418 | an older model 77d:223) */ | ||
419 | /* | ||
420 | * plantronics headset and Griffin iMic have set adaptive-in | ||
421 | * although it's really not... | ||
422 | */ | ||
423 | fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; | ||
424 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
425 | fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; | ||
426 | else | ||
427 | fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | /* ok, let's parse further... */ | ||
432 | if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { | ||
433 | kfree(fp->rate_table); | ||
434 | kfree(fp); | ||
435 | fp = NULL; | ||
436 | continue; | ||
437 | } | ||
438 | |||
439 | snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); | ||
440 | err = snd_usb_add_audio_stream(chip, stream, fp); | ||
441 | if (err < 0) { | ||
442 | kfree(fp->rate_table); | ||
443 | kfree(fp); | ||
444 | return err; | ||
445 | } | ||
446 | /* try to set the interface... */ | ||
447 | usb_set_interface(chip->dev, iface_no, altno); | ||
448 | snd_usb_init_pitch(chip, iface_no, alts, fp); | ||
449 | snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); | ||
450 | } | ||
451 | return 0; | ||
452 | } | ||
453 | |||
diff --git a/sound/usb/stream.h b/sound/usb/stream.h new file mode 100644 index 000000000000..c97f679fc84f --- /dev/null +++ b/sound/usb/stream.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef __USBAUDIO_STREAM_H | ||
2 | #define __USBAUDIO_STREAM_H | ||
3 | |||
4 | int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, | ||
5 | int iface_no); | ||
6 | |||
7 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | ||
8 | int stream, | ||
9 | struct audioformat *fp); | ||
10 | |||
11 | #endif /* __USBAUDIO_STREAM_H */ | ||
12 | |||