diff options
Diffstat (limited to 'sound/usb/urb.c')
-rw-r--r-- | sound/usb/urb.c | 170 |
1 files changed, 58 insertions, 112 deletions
diff --git a/sound/usb/urb.c b/sound/usb/urb.c index 8deeaad10f10..e184349aee83 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c | |||
@@ -225,6 +225,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, | |||
225 | else | 225 | else |
226 | subs->freqn = get_usb_high_speed_rate(rate); | 226 | subs->freqn = get_usb_high_speed_rate(rate); |
227 | subs->freqm = subs->freqn; | 227 | subs->freqm = subs->freqn; |
228 | subs->freqshift = INT_MIN; | ||
228 | /* calculate max. frequency */ | 229 | /* calculate max. frequency */ |
229 | if (subs->maxpacksize) { | 230 | if (subs->maxpacksize) { |
230 | /* whatever fits into a max. size packet */ | 231 | /* whatever fits into a max. size packet */ |
@@ -513,11 +514,10 @@ static int retire_paused_capture_urb(struct snd_usb_substream *subs, | |||
513 | 514 | ||
514 | 515 | ||
515 | /* | 516 | /* |
516 | * prepare urb for full speed playback sync pipe | 517 | * prepare urb for playback sync pipe |
517 | * | 518 | * |
518 | * set up the offset and length to receive the current frequency. | 519 | * set up the offset and length to receive the current frequency. |
519 | */ | 520 | */ |
520 | |||
521 | static int prepare_playback_sync_urb(struct snd_usb_substream *subs, | 521 | static int prepare_playback_sync_urb(struct snd_usb_substream *subs, |
522 | struct snd_pcm_runtime *runtime, | 522 | struct snd_pcm_runtime *runtime, |
523 | struct urb *urb) | 523 | struct urb *urb) |
@@ -525,103 +525,78 @@ static int prepare_playback_sync_urb(struct snd_usb_substream *subs, | |||
525 | struct snd_urb_ctx *ctx = urb->context; | 525 | struct snd_urb_ctx *ctx = urb->context; |
526 | 526 | ||
527 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 527 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
528 | urb->iso_frame_desc[0].length = 3; | 528 | urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize); |
529 | urb->iso_frame_desc[0].offset = 0; | 529 | urb->iso_frame_desc[0].offset = 0; |
530 | return 0; | 530 | return 0; |
531 | } | 531 | } |
532 | 532 | ||
533 | /* | 533 | /* |
534 | * prepare urb for high speed playback sync pipe | 534 | * process after playback sync complete |
535 | * | 535 | * |
536 | * set up the offset and length to receive the current frequency. | 536 | * Full speed devices report feedback values in 10.14 format as samples per |
537 | */ | 537 | * frame, high speed devices in 16.16 format as samples per microframe. |
538 | 538 | * Because the Audio Class 1 spec was written before USB 2.0, many high speed | |
539 | static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, | 539 | * devices use a wrong interpretation, some others use an entirely different |
540 | struct snd_pcm_runtime *runtime, | 540 | * format. Therefore, we cannot predict what format any particular device uses |
541 | struct urb *urb) | 541 | * and must detect it automatically. |
542 | { | ||
543 | struct snd_urb_ctx *ctx = urb->context; | ||
544 | |||
545 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | ||
546 | urb->iso_frame_desc[0].length = 4; | ||
547 | urb->iso_frame_desc[0].offset = 0; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * process after full speed playback sync complete | ||
553 | * | ||
554 | * retrieve the current 10.14 frequency from pipe, and set it. | ||
555 | * the value is referred in prepare_playback_urb(). | ||
556 | */ | 542 | */ |
557 | static int retire_playback_sync_urb(struct snd_usb_substream *subs, | 543 | static int retire_playback_sync_urb(struct snd_usb_substream *subs, |
558 | struct snd_pcm_runtime *runtime, | 544 | struct snd_pcm_runtime *runtime, |
559 | struct urb *urb) | 545 | struct urb *urb) |
560 | { | 546 | { |
561 | unsigned int f; | 547 | unsigned int f; |
548 | int shift; | ||
562 | unsigned long flags; | 549 | unsigned long flags; |
563 | 550 | ||
564 | if (urb->iso_frame_desc[0].status == 0 && | 551 | if (urb->iso_frame_desc[0].status != 0 || |
565 | urb->iso_frame_desc[0].actual_length == 3) { | 552 | urb->iso_frame_desc[0].actual_length < 3) |
566 | f = combine_triple((u8*)urb->transfer_buffer) << 2; | 553 | return 0; |
567 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { | ||
568 | spin_lock_irqsave(&subs->lock, flags); | ||
569 | subs->freqm = f; | ||
570 | spin_unlock_irqrestore(&subs->lock, flags); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | 554 | ||
577 | /* | 555 | f = le32_to_cpup(urb->transfer_buffer); |
578 | * process after high speed playback sync complete | 556 | if (urb->iso_frame_desc[0].actual_length == 3) |
579 | * | 557 | f &= 0x00ffffff; |
580 | * retrieve the current 12.13 frequency from pipe, and set it. | 558 | else |
581 | * the value is referred in prepare_playback_urb(). | 559 | f &= 0x0fffffff; |
582 | */ | 560 | if (f == 0) |
583 | static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs, | 561 | return 0; |
584 | struct snd_pcm_runtime *runtime, | ||
585 | struct urb *urb) | ||
586 | { | ||
587 | unsigned int f; | ||
588 | unsigned long flags; | ||
589 | 562 | ||
590 | if (urb->iso_frame_desc[0].status == 0 && | 563 | if (unlikely(subs->freqshift == INT_MIN)) { |
591 | urb->iso_frame_desc[0].actual_length == 4) { | 564 | /* |
592 | f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; | 565 | * The first time we see a feedback value, determine its format |
593 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { | 566 | * by shifting it left or right until it matches the nominal |
594 | spin_lock_irqsave(&subs->lock, flags); | 567 | * frequency value. This assumes that the feedback does not |
595 | subs->freqm = f; | 568 | * differ from the nominal value more than +50% or -25%. |
596 | spin_unlock_irqrestore(&subs->lock, flags); | 569 | */ |
570 | shift = 0; | ||
571 | while (f < subs->freqn - subs->freqn / 4) { | ||
572 | f <<= 1; | ||
573 | shift++; | ||
574 | } | ||
575 | while (f > subs->freqn + subs->freqn / 2) { | ||
576 | f >>= 1; | ||
577 | shift--; | ||
597 | } | 578 | } |
579 | subs->freqshift = shift; | ||
598 | } | 580 | } |
581 | else if (subs->freqshift >= 0) | ||
582 | f <<= subs->freqshift; | ||
583 | else | ||
584 | f >>= -subs->freqshift; | ||
599 | 585 | ||
600 | return 0; | 586 | if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) { |
601 | } | 587 | /* |
602 | 588 | * If the frequency looks valid, set it. | |
603 | /* | 589 | * This value is referred to in prepare_playback_urb(). |
604 | * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete | 590 | */ |
605 | * | 591 | spin_lock_irqsave(&subs->lock, flags); |
606 | * These devices return the number of samples per packet instead of the number | 592 | subs->freqm = f; |
607 | * of samples per microframe. | 593 | spin_unlock_irqrestore(&subs->lock, flags); |
608 | */ | 594 | } else { |
609 | static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs, | 595 | /* |
610 | struct snd_pcm_runtime *runtime, | 596 | * Out of range; maybe the shift value is wrong. |
611 | struct urb *urb) | 597 | * Reset it so that we autodetect again the next time. |
612 | { | 598 | */ |
613 | unsigned int f; | 599 | subs->freqshift = INT_MIN; |
614 | unsigned long flags; | ||
615 | |||
616 | if (urb->iso_frame_desc[0].status == 0 && | ||
617 | urb->iso_frame_desc[0].actual_length == 4) { | ||
618 | f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; | ||
619 | f >>= subs->datainterval; | ||
620 | if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { | ||
621 | spin_lock_irqsave(&subs->lock, flags); | ||
622 | subs->freqm = f; | ||
623 | spin_unlock_irqrestore(&subs->lock, flags); | ||
624 | } | ||
625 | } | 600 | } |
626 | 601 | ||
627 | return 0; | 602 | return 0; |
@@ -878,21 +853,6 @@ static struct snd_urb_ops audio_urb_ops[2] = { | |||
878 | }, | 853 | }, |
879 | }; | 854 | }; |
880 | 855 | ||
881 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { | ||
882 | { | ||
883 | .prepare = prepare_nodata_playback_urb, | ||
884 | .retire = retire_playback_urb, | ||
885 | .prepare_sync = prepare_playback_sync_urb_hs, | ||
886 | .retire_sync = retire_playback_sync_urb_hs, | ||
887 | }, | ||
888 | { | ||
889 | .prepare = prepare_capture_urb, | ||
890 | .retire = retire_capture_urb, | ||
891 | .prepare_sync = prepare_capture_sync_urb_hs, | ||
892 | .retire_sync = retire_capture_sync_urb, | ||
893 | }, | ||
894 | }; | ||
895 | |||
896 | /* | 856 | /* |
897 | * initialize the substream instance. | 857 | * initialize the substream instance. |
898 | */ | 858 | */ |
@@ -909,23 +869,9 @@ void snd_usb_init_substream(struct snd_usb_stream *as, | |||
909 | subs->direction = stream; | 869 | subs->direction = stream; |
910 | subs->dev = as->chip->dev; | 870 | subs->dev = as->chip->dev; |
911 | subs->txfr_quirk = as->chip->txfr_quirk; | 871 | subs->txfr_quirk = as->chip->txfr_quirk; |
912 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { | 872 | subs->ops = audio_urb_ops[stream]; |
913 | subs->ops = audio_urb_ops[stream]; | 873 | if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) |
914 | } else { | 874 | subs->ops.prepare_sync = prepare_capture_sync_urb_hs; |
915 | subs->ops = audio_urb_ops_high_speed[stream]; | ||
916 | switch (as->chip->usb_id) { | ||
917 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
918 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
919 | case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ | ||
920 | subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; | ||
921 | break; | ||
922 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ | ||
923 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
924 | subs->ops.prepare_sync = prepare_playback_sync_urb; | ||
925 | subs->ops.retire_sync = retire_playback_sync_urb; | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | 875 | ||
930 | snd_usb_set_pcm_ops(as->pcm, stream); | 876 | snd_usb_set_pcm_ops(as->pcm, stream); |
931 | 877 | ||