aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/usbaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r--sound/usb/usbaudio.c41
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 */
641static int retire_playback_urb(struct snd_usb_substream *subs, 642static 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 */
3300static 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 */