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