diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-02-25 05:01:00 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-02-29 05:28:15 -0500 |
commit | d513202efd5bb9974545ef1c7f951467b21eb3a5 (patch) | |
tree | 56dd0f3aa631713717b6e0415d410be99432e7c9 | |
parent | ee47fd12d73706edb2a10efd05d5eed15b4d1e08 (diff) |
[ALSA] usb-audio: add workaround for broken E-Mu frequency feedback
Add a workaround for the feedback pipe of E-Mu 0202/0404 USB devices
that reports the number of samples per packet instead of the number of
samples per microframe.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/usb/usbaudio.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8fa935665702..675672f313be 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 | { |
@@ -2219,10 +2246,17 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo | |||
2219 | subs->stream = as; | 2246 | subs->stream = as; |
2220 | subs->direction = stream; | 2247 | subs->direction = stream; |
2221 | subs->dev = as->chip->dev; | 2248 | subs->dev = as->chip->dev; |
2222 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 2249 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { |
2223 | subs->ops = audio_urb_ops[stream]; | 2250 | subs->ops = audio_urb_ops[stream]; |
2224 | else | 2251 | } else { |
2225 | subs->ops = audio_urb_ops_high_speed[stream]; | 2252 | subs->ops = audio_urb_ops_high_speed[stream]; |
2253 | switch (as->chip->usb_id) { | ||
2254 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
2255 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
2256 | subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; | ||
2257 | break; | ||
2258 | } | ||
2259 | } | ||
2226 | snd_pcm_set_ops(as->pcm, stream, | 2260 | snd_pcm_set_ops(as->pcm, stream, |
2227 | stream == SNDRV_PCM_STREAM_PLAYBACK ? | 2261 | stream == SNDRV_PCM_STREAM_PLAYBACK ? |
2228 | &snd_usb_playback_ops : &snd_usb_capture_ops); | 2262 | &snd_usb_playback_ops : &snd_usb_capture_ops); |