diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/usbaudio.c | 39 | ||||
-rw-r--r-- | sound/usb/usbquirks.h | 43 |
2 files changed, 81 insertions, 1 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6b88482637..c7b902358b7 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, subs->hwptr_done += offs; if (subs->hwptr_done >= runtime->buffer_size) subs->hwptr_done -= runtime->buffer_size; + runtime->delay += offs; spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; if (period_elapsed) @@ -636,12 +637,22 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, /* * process after playback data complete - * - nothing to do + * - decrease the delay count again */ static int retire_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { + unsigned long flags; + int stride = runtime->frame_bits >> 3; + int processed = urb->transfer_buffer_length / stride; + + spin_lock_irqsave(&subs->lock, flags); + if (processed > runtime->delay) + runtime->delay = 0; + else + runtime->delay -= processed; + spin_unlock_irqrestore(&subs->lock, flags); return 0; } @@ -1520,6 +1531,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; + runtime->delay = 0; /* clear urbs (to be sure) */ deactivate_urbs(subs, 0, 1); @@ -3279,6 +3291,25 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); } +/* + * C-Media CM6206 is based on CM106 with two additional + * registers that are not documented in the data sheet. + * Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) +{ + int err, reg; + int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; + + for (reg = 0; reg < ARRAY_SIZE(val); reg++) { + err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); + if (err < 0) + return err; + } + + return err; +} /* * Setup quirks @@ -3565,6 +3596,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; } + /* C-Media CM6206 / CM106-Like Sound Device */ + if (id == USB_ID(0x0d8c, 0x0102)) { + if (snd_usb_cm6206_boot_quirk(dev) < 0) + goto __err_val; + } + /* * found a config. now register to ALSA */ diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 5d955aaad85..f0f7624f917 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1470,6 +1470,41 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* Edirol M-16DX */ + /* FIXME: This quirk gives a good-working capture stream but the + * playback seems problematic because of lacking of sync + * with capture stream. It needs to sync with the capture + * clock. As now, you'll get frequent sound distortions + * via the playback. + */ + USB_DEVICE(0x0582, 0x00c4), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ /* BOSS GT-10 */ USB_DEVICE(0x0582, 0x00da), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1951,6 +1986,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + USB_DEVICE(0x0ccd, 0x0028), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "TerraTec", + .product_name = "Aureon 5.1 MkII", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ USB_DEVICE(0x0ccd, 0x0035), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "Miditech", |