diff options
-rw-r--r-- | sound/usb/pcm.c | 37 |
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 | |||
360 | add_sync_ep: | 374 | add_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 | ||