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); |
