diff options
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r-- | sound/usb/usbaudio.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 823296d7d578..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 |
@@ -3347,7 +3378,7 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
3347 | [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, | 3378 | [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, |
3348 | [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, | 3379 | [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, |
3349 | [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, | 3380 | [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, |
3350 | [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, | 3381 | [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, |
3351 | [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, | 3382 | [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, |
3352 | [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, | 3383 | [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, |
3353 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, | 3384 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
@@ -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 | */ |