diff options
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r-- | sound/usb/usbaudio.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8fa935665702..f48838a078cb 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -479,6 +479,33 @@ static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs, | |||
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | /* | ||
483 | * process after E-Mu 0202/0404 high speed playback sync complete | ||
484 | * | ||
485 | * These devices return the number of samples per packet instead of the number | ||
486 | * of samples per microframe. | ||
487 | */ | ||
488 | static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs, | ||
489 | struct snd_pcm_runtime *runtime, | ||
490 | struct urb *urb) | ||
491 | { | ||
492 | unsigned int f; | ||
493 | unsigned long flags; | ||
494 | |||
495 | if (urb->iso_frame_desc[0].status == 0 && | ||
496 | urb->iso_frame_desc[0].actual_length == 4) { | ||
497 | f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; | ||
498 | f >>= subs->datainterval; | ||
499 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { | ||
500 | spin_lock_irqsave(&subs->lock, flags); | ||
501 | subs->freqm = f; | ||
502 | spin_unlock_irqrestore(&subs->lock, flags); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
482 | /* determine the number of frames in the next packet */ | 509 | /* determine the number of frames in the next packet */ |
483 | static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) | 510 | static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) |
484 | { | 511 | { |
@@ -1735,6 +1762,8 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1735 | 1762 | ||
1736 | channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); | 1763 | channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); |
1737 | rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); | 1764 | rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); |
1765 | if (!channels || !rates) | ||
1766 | goto __out; | ||
1738 | 1767 | ||
1739 | list_for_each(p, &subs->fmt_list) { | 1768 | list_for_each(p, &subs->fmt_list) { |
1740 | struct audioformat *f; | 1769 | struct audioformat *f; |
@@ -2219,10 +2248,17 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo | |||
2219 | subs->stream = as; | 2248 | subs->stream = as; |
2220 | subs->direction = stream; | 2249 | subs->direction = stream; |
2221 | subs->dev = as->chip->dev; | 2250 | subs->dev = as->chip->dev; |
2222 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 2251 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { |
2223 | subs->ops = audio_urb_ops[stream]; | 2252 | subs->ops = audio_urb_ops[stream]; |
2224 | else | 2253 | } else { |
2225 | subs->ops = audio_urb_ops_high_speed[stream]; | 2254 | subs->ops = audio_urb_ops_high_speed[stream]; |
2255 | switch (as->chip->usb_id) { | ||
2256 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
2257 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
2258 | subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; | ||
2259 | break; | ||
2260 | } | ||
2261 | } | ||
2226 | snd_pcm_set_ops(as->pcm, stream, | 2262 | snd_pcm_set_ops(as->pcm, stream, |
2227 | stream == SNDRV_PCM_STREAM_PLAYBACK ? | 2263 | stream == SNDRV_PCM_STREAM_PLAYBACK ? |
2228 | &snd_usb_playback_ops : &snd_usb_capture_ops); | 2264 | &snd_usb_playback_ops : &snd_usb_capture_ops); |