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)
/*
* 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;
}
} else
urb_packs = 1;
urb_packs *= packs_per_ms;
+ if (subs->syncpipe)
+ urb_packs = min(urb_packs, 1U << subs->syncinterval);
/* decide how many packets to be used */
if (is_playback) {
subs->hwptr_done = 0;
subs->transfer_done = 0;
subs->phase = 0;
+ runtime->delay = 0;
/* clear urbs (to be sure) */
deactivate_urbs(subs, 0, 1);
fp = list_entry(p, struct audioformat, list);
snd_iprintf(buffer, " Interface %d\n", fp->iface);
snd_iprintf(buffer, " Altset %d\n", fp->altsetting);
- snd_iprintf(buffer, " Format: %#x (%d bits)\n",
- fp->format, snd_pcm_format_width(fp->format));
+ snd_iprintf(buffer, " Format: %s\n",
+ snd_pcm_format_name(fp->format));
snd_iprintf(buffer, " Channels: %d\n", fp->channels);
snd_iprintf(buffer, " Endpoint: %d %s (%s)\n",
fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
int format;
- struct audioformat *fp;
+ struct audioformat *fp = NULL;
unsigned char *fmt, *csep;
int num;
continue;
}
+ /*
+ * Blue Microphones workaround: The last altsetting is identical
+ * with the previous one, except for a larger packet size, but
+ * is actually a mislabeled two-channel setting; ignore it.
+ */
+ if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 &&
+ fp && fp->altsetting == 1 && fp->channels == 1 &&
+ fp->format == SNDRV_PCM_FORMAT_S16_LE &&
+ le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
+ fp->maxpacksize * 2)
+ continue;
+
csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
/* Creamware Noah has this descriptor after the 2nd endpoint */
if (!csep && altsd->bNumEndpoints >= 2)
if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
- if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
+ int err = snd_usbmidi_create(chip->card, iface,
+ &chip->midi_list, NULL);
+ if (err < 0) {
snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
continue;
}
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = &uaxx_ep
};
- if (chip->usb_id == USB_ID(0x0582, 0x002b))
- return snd_usb_create_midi_interface(chip, iface,
- &ua700_quirk);
- else
- return snd_usb_create_midi_interface(chip, iface,
- &uaxx_quirk);
+ const struct snd_usb_audio_quirk *quirk =
+ chip->usb_id == USB_ID(0x0582, 0x002b)
+ ? &ua700_quirk : &uaxx_quirk;
+ return snd_usbmidi_create(chip->card, iface,
+ &chip->midi_list, quirk);
}
if (altsd->bNumEndpoints != 1)
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
return 0; /* keep this altsetting */
}
+static int create_any_midi_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *intf,
+ const struct snd_usb_audio_quirk *quirk)
+{
+ return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk);
+}
+
/*
* audio-interface quirks
*
static const quirk_func_t quirk_funcs[] = {
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
[QUIRK_COMPOSITE] = create_composite_quirk,
- [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
- [QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
+ [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
+ [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
+ [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
+ [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
+ [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+ [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
+ [QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
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
*/