diff options
Diffstat (limited to 'sound/usb/usbaudio.c')
| -rw-r--r-- | sound/usb/usbaudio.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6b88482637b..c7b902358b7b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
| @@ -627,6 +627,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
| 627 | subs->hwptr_done += offs; | 627 | subs->hwptr_done += offs; |
| 628 | if (subs->hwptr_done >= runtime->buffer_size) | 628 | if (subs->hwptr_done >= runtime->buffer_size) |
| 629 | subs->hwptr_done -= runtime->buffer_size; | 629 | subs->hwptr_done -= runtime->buffer_size; |
| 630 | runtime->delay += offs; | ||
| 630 | spin_unlock_irqrestore(&subs->lock, flags); | 631 | spin_unlock_irqrestore(&subs->lock, flags); |
| 631 | urb->transfer_buffer_length = offs * stride; | 632 | urb->transfer_buffer_length = offs * stride; |
| 632 | if (period_elapsed) | 633 | if (period_elapsed) |
| @@ -636,12 +637,22 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
| 636 | 637 | ||
| 637 | /* | 638 | /* |
| 638 | * process after playback data complete | 639 | * process after playback data complete |
| 639 | * - nothing to do | 640 | * - decrease the delay count again |
| 640 | */ | 641 | */ |
| 641 | static int retire_playback_urb(struct snd_usb_substream *subs, | 642 | static int retire_playback_urb(struct snd_usb_substream *subs, |
| 642 | struct snd_pcm_runtime *runtime, | 643 | struct snd_pcm_runtime *runtime, |
| 643 | struct urb *urb) | 644 | struct urb *urb) |
| 644 | { | 645 | { |
| 646 | unsigned long flags; | ||
| 647 | int stride = runtime->frame_bits >> 3; | ||
| 648 | int processed = urb->transfer_buffer_length / stride; | ||
| 649 | |||
| 650 | spin_lock_irqsave(&subs->lock, flags); | ||
| 651 | if (processed > runtime->delay) | ||
| 652 | runtime->delay = 0; | ||
| 653 | else | ||
| 654 | runtime->delay -= processed; | ||
| 655 | spin_unlock_irqrestore(&subs->lock, flags); | ||
| 645 | return 0; | 656 | return 0; |
| 646 | } | 657 | } |
| 647 | 658 | ||
| @@ -1520,6 +1531,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 1520 | subs->hwptr_done = 0; | 1531 | subs->hwptr_done = 0; |
| 1521 | subs->transfer_done = 0; | 1532 | subs->transfer_done = 0; |
| 1522 | subs->phase = 0; | 1533 | subs->phase = 0; |
| 1534 | runtime->delay = 0; | ||
| 1523 | 1535 | ||
| 1524 | /* clear urbs (to be sure) */ | 1536 | /* clear urbs (to be sure) */ |
| 1525 | deactivate_urbs(subs, 0, 1); | 1537 | deactivate_urbs(subs, 0, 1); |
| @@ -3279,6 +3291,25 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) | |||
| 3279 | return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); | 3291 | return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); |
| 3280 | } | 3292 | } |
| 3281 | 3293 | ||
| 3294 | /* | ||
| 3295 | * C-Media CM6206 is based on CM106 with two additional | ||
| 3296 | * registers that are not documented in the data sheet. | ||
| 3297 | * Values here are chosen based on sniffing USB traffic | ||
| 3298 | * under Windows. | ||
| 3299 | */ | ||
| 3300 | static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) | ||
| 3301 | { | ||
| 3302 | int err, reg; | ||
| 3303 | int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; | ||
| 3304 | |||
| 3305 | for (reg = 0; reg < ARRAY_SIZE(val); reg++) { | ||
| 3306 | err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); | ||
| 3307 | if (err < 0) | ||
| 3308 | return err; | ||
| 3309 | } | ||
| 3310 | |||
| 3311 | return err; | ||
| 3312 | } | ||
| 3282 | 3313 | ||
| 3283 | /* | 3314 | /* |
| 3284 | * Setup quirks | 3315 | * Setup quirks |
| @@ -3565,6 +3596,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
| 3565 | goto __err_val; | 3596 | goto __err_val; |
| 3566 | } | 3597 | } |
| 3567 | 3598 | ||
| 3599 | /* C-Media CM6206 / CM106-Like Sound Device */ | ||
| 3600 | if (id == USB_ID(0x0d8c, 0x0102)) { | ||
| 3601 | if (snd_usb_cm6206_boot_quirk(dev) < 0) | ||
| 3602 | goto __err_val; | ||
| 3603 | } | ||
| 3604 | |||
| 3568 | /* | 3605 | /* |
| 3569 | * found a config. now register to ALSA | 3606 | * found a config. now register to ALSA |
| 3570 | */ | 3607 | */ |
