aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/usb/pcm.c37
1 files changed, 26 insertions, 11 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0f107834c100..2d3a04d829b7 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -301,7 +301,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
301 struct usb_interface *iface; 301 struct usb_interface *iface;
302 unsigned int ep, attr; 302 unsigned int ep, attr;
303 int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; 303 int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
304 int err; 304 int err, implicit_fb = 0;
305 305
306 iface = usb_ifnum_to_if(dev, fmt->iface); 306 iface = usb_ifnum_to_if(dev, fmt->iface);
307 if (WARN_ON(!iface)) 307 if (WARN_ON(!iface))
@@ -326,25 +326,34 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
326 * assume it as adaptive-out or sync-in. 326 * assume it as adaptive-out or sync-in.
327 */ 327 */
328 attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; 328 attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
329 if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || 329
330 (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && 330 switch (subs->stream->chip->usb_id) {
331 altsd->bNumEndpoints >= 2) { 331 case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
332 switch (subs->stream->chip->usb_id) { 332 case USB_ID(0x0763, 0x2081):
333 case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ 333 if (is_playback) {
334 case USB_ID(0x0763, 0x2081): 334 implicit_fb = 1;
335 ep = 0x81; 335 ep = 0x81;
336 iface = usb_ifnum_to_if(dev, 2); 336 iface = usb_ifnum_to_if(dev, 2);
337
338 if (!iface || iface->num_altsetting == 0)
339 return -EINVAL;
340
337 alts = &iface->altsetting[1]; 341 alts = &iface->altsetting[1];
338 goto add_sync_ep; 342 goto add_sync_ep;
339 } 343 }
344 }
340 345
346 if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
347 (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
348 altsd->bNumEndpoints >= 2) {
341 /* check sync-pipe endpoint */ 349 /* check sync-pipe endpoint */
342 /* ... and check descriptor size before accessing bSynchAddress 350 /* ... and check descriptor size before accessing bSynchAddress
343 because there is a version of the SB Audigy 2 NX firmware lacking 351 because there is a version of the SB Audigy 2 NX firmware lacking
344 the audio fields in the endpoint descriptors */ 352 the audio fields in the endpoint descriptors */
345 if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || 353 if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
346 (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && 354 (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
347 get_endpoint(alts, 1)->bSynchAddress != 0)) { 355 get_endpoint(alts, 1)->bSynchAddress != 0 &&
356 !implicit_fb)) {
348 snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", 357 snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
349 dev->devnum, fmt->iface, fmt->altsetting); 358 dev->devnum, fmt->iface, fmt->altsetting);
350 return -EINVAL; 359 return -EINVAL;
@@ -352,16 +361,22 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
352 ep = get_endpoint(alts, 1)->bEndpointAddress; 361 ep = get_endpoint(alts, 1)->bEndpointAddress;
353 if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && 362 if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
354 (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || 363 (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
355 (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { 364 (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
365 ( is_playback && !implicit_fb))) {
356 snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", 366 snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
357 dev->devnum, fmt->iface, fmt->altsetting); 367 dev->devnum, fmt->iface, fmt->altsetting);
358 return -EINVAL; 368 return -EINVAL;
359 } 369 }
370
371 implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
372 == USB_ENDPOINT_USAGE_IMPLICIT_FB;
373
360add_sync_ep: 374add_sync_ep:
361 subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, 375 subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
362 alts, ep, !subs->direction, 376 alts, ep, !subs->direction,
363 SND_USB_ENDPOINT_TYPE_SYNC); 377 implicit_fb ?
364 378 SND_USB_ENDPOINT_TYPE_DATA :
379 SND_USB_ENDPOINT_TYPE_SYNC);
365 if (!subs->sync_endpoint) 380 if (!subs->sync_endpoint)
366 return -EINVAL; 381 return -EINVAL;
367 382