summaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/caiaq/device.c8
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/mixer.c1
-rw-r--r--sound/usb/mixer_maps.c4
-rw-r--r--sound/usb/mixer_quirks.c72
-rw-r--r--sound/usb/pcm.c26
-rw-r--r--sound/usb/quirks-table.h73
-rw-r--r--sound/usb/quirks.c13
8 files changed, 166 insertions, 33 deletions
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index c828f8189c2..e4d6dbb0342 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -48,10 +48,10 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Traktor Audio 2},"
"{Native Instruments, Session I/O},"
- "{Native Instruments, GuitarRig mobile}"
- "{Native Instruments, Traktor Kontrol X1}"
- "{Native Instruments, Traktor Kontrol S4}"
- "{Native Instruments, Maschine Controller}");
+ "{Native Instruments, GuitarRig mobile},"
+ "{Native Instruments, Traktor Kontrol X1},"
+ "{Native Instruments, Traktor Kontrol S4},"
+ "{Native Instruments, Maschine Controller}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
diff --git a/sound/usb/card.c b/sound/usb/card.c
index ccf95cfe186..803953a9bff 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -646,7 +646,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
as->substream[0].need_setup_ep =
as->substream[1].need_setup_ep = true;
}
- }
+ }
} else {
/*
* otherwise we keep the rest of the system in the dark
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e90daf8cdaa..638e7f73801 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -807,6 +807,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
{
switch (cval->mixer->chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
+ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
if (strcmp(kctl->id.name, "Effect Duration") == 0) {
cval->min = 0x0000;
cval->max = 0xffff;
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 0e2ed3d05c4..cc2dd1f0dec 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -380,6 +380,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.selector_map = c400_selectors,
},
{
+ .id = USB_ID(0x0763, 0x2031),
+ .selector_map = c400_selectors,
+ },
+ {
.id = USB_ID(0x08bb, 0x2702),
.map = linex_map,
.ignore_ctl_error = 1,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 15520de1df5..497d2741d11 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -637,7 +637,7 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
}
/* M-Audio FastTrack Ultra quirks */
-/* FTU Effect switch (also used by C400) */
+/* FTU Effect switch (also used by C400/C600) */
struct snd_ftu_eff_switch_priv_val {
struct usb_mixer_interface *mixer;
int cached_value;
@@ -1029,32 +1029,45 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
}
}
-/* M-Audio Fast Track C400 */
-/* C400 volume controls, this control needs a volume quirk, see mixer.c */
+/* M-Audio Fast Track C400/C600 */
+/* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */
static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer)
{
char name[64];
unsigned int cmask, offset;
int out, chan, err;
+ int num_outs = 0;
+ int num_ins = 0;
const unsigned int id = 0x40;
const int val_type = USB_MIXER_S16;
const int control = 1;
- for (chan = 0; chan < 10; chan++) {
- for (out = 0; out < 6; out++) {
- if (chan < 6) {
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x0763, 0x2030):
+ num_outs = 6;
+ num_ins = 4;
+ break;
+ case USB_ID(0x0763, 0x2031):
+ num_outs = 8;
+ num_ins = 6;
+ break;
+ }
+
+ for (chan = 0; chan < num_outs + num_ins; chan++) {
+ for (out = 0; out < num_outs; out++) {
+ if (chan < num_outs) {
snprintf(name, sizeof(name),
"PCM%d-Out%d Playback Volume",
chan + 1, out + 1);
} else {
snprintf(name, sizeof(name),
"In%d-Out%d Playback Volume",
- chan - 5, out + 1);
+ chan - num_outs + 1, out + 1);
}
cmask = (out == 0) ? 0 : 1 << (out - 1);
- offset = chan * 6;
+ offset = chan * num_outs;
err = snd_create_std_mono_ctl_offset(mixer, id, control,
cmask, val_type, offset, name,
&snd_usb_mixer_vol_tlv);
@@ -1110,20 +1123,33 @@ static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer)
char name[64];
unsigned int cmask;
int chan, err;
+ int num_outs = 0;
+ int num_ins = 0;
const unsigned int id = 0x42;
const int val_type = USB_MIXER_S16;
const int control = 1;
- for (chan = 0; chan < 10; chan++) {
- if (chan < 6) {
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x0763, 0x2030):
+ num_outs = 6;
+ num_ins = 4;
+ break;
+ case USB_ID(0x0763, 0x2031):
+ num_outs = 8;
+ num_ins = 6;
+ break;
+ }
+
+ for (chan = 0; chan < num_outs + num_ins; chan++) {
+ if (chan < num_outs) {
snprintf(name, sizeof(name),
"Effect Send DOut%d",
chan + 1);
} else {
snprintf(name, sizeof(name),
"Effect Send AIn%d",
- chan - 5);
+ chan - num_outs + 1);
}
cmask = (chan == 0) ? 0 : 1 << (chan - 1);
@@ -1142,20 +1168,33 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer
char name[64];
unsigned int cmask;
int chan, err;
+ int num_outs = 0;
+ int offset = 0;
const unsigned int id = 0x40;
const int val_type = USB_MIXER_S16;
const int control = 1;
- const int chan_id[6] = { 0, 7, 2, 9, 4, 0xb };
- const unsigned int offset = 0x3c;
- /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */
- for (chan = 0; chan < 6; chan++) {
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x0763, 0x2030):
+ num_outs = 6;
+ offset = 0x3c;
+ /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */
+ break;
+ case USB_ID(0x0763, 0x2031):
+ num_outs = 8;
+ offset = 0x70;
+ /* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */
+ break;
+ }
+
+ for (chan = 0; chan < num_outs; chan++) {
snprintf(name, sizeof(name),
"Effect Return %d",
chan + 1);
- cmask = (chan_id[chan] == 0) ? 0 : 1 << (chan_id[chan] - 1);
+ cmask = (chan == 0) ? 0 :
+ 1 << (chan + (chan % 2) * num_outs - 1);
err = snd_create_std_mono_ctl_offset(mixer, id, control,
cmask, val_type, offset, name,
&snd_usb_mixer_vol_tlv);
@@ -1299,6 +1338,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
break;
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
+ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */
err = snd_c400_create_mixer(mixer);
break;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index d82e378d37c..f94397b42aa 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -59,7 +59,12 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
/* Approximation based on number of samples per USB frame (ms),
some truncation for 44.1 but the estimate is good enough */
- est_delay = subs->last_delay - (frame_diff * rate / 1000);
+ est_delay = frame_diff * rate / 1000;
+ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ est_delay = subs->last_delay - est_delay;
+ else
+ est_delay = subs->last_delay + est_delay;
+
if (est_delay < 0)
est_delay = 0;
return est_delay;
@@ -78,8 +83,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
return SNDRV_PCM_POS_XRUN;
spin_lock(&subs->lock);
hwptr_done = subs->hwptr_done;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- substream->runtime->delay = snd_usb_pcm_delay(subs,
+ substream->runtime->delay = snd_usb_pcm_delay(subs,
substream->runtime->rate);
spin_unlock(&subs->lock);
return hwptr_done / (substream->runtime->frame_bits >> 3);
@@ -363,6 +367,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
switch (subs->stream->chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
+ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
if (is_playback) {
implicit_fb = 1;
ep = 0x81;
@@ -1157,6 +1162,10 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
int i, period_elapsed = 0;
unsigned long flags;
unsigned char *cp;
+ int current_frame_number;
+
+ /* read frame number here, update pointer in critical section */
+ current_frame_number = usb_get_current_frame_number(subs->dev);
stride = runtime->frame_bits >> 3;
@@ -1171,9 +1180,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
if (!subs->txfr_quirk)
bytes = frames * stride;
if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
int oldbytes = bytes;
-#endif
bytes = frames * stride;
snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
oldbytes, bytes);
@@ -1190,6 +1197,15 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
}
+ /* capture delay is by construction limited to one URB,
+ * reset delays here
+ */
+ runtime->delay = subs->last_delay = 0;
+
+ /* realign last_frame_number */
+ subs->last_frame_number = current_frame_number;
+ subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
+
spin_unlock_irqrestore(&subs->lock, flags);
/* copy a data chunk */
if (oldptr + bytes > runtime->buffer_size * stride) {
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 64d25a7a4d5..c39f898b15d 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1750,7 +1750,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "Roland", */
/* .product_name = "A-PRO", */
- .ifnum = 1,
+ .ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const struct snd_usb_midi_endpoint_info) {
.out_cables = 0x0003,
@@ -2326,6 +2326,77 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ /* .vendor_name = "M-Audio", */
+ /* .product_name = "Fast Track C600", */
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = &(const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
+ },
+ /* Playback */
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 8,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = 0x09,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ },
+ .clock = 0x80,
+ }
+ },
+ /* Capture */
+ {
+ .ifnum = 3,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 6,
+ .iface = 3,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x81,
+ .ep_attr = 0x05,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .nr_rates = 4,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000, 88200, 96000
+ },
+ .clock = 0x80,
+ }
+ },
+ /* MIDI */
+ {
+ .ifnum = -1 /* Interface = 4 */
+ }
+ }
+ }
+},
+{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "M-Audio", */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 2c971858d6b..5325a3869bb 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -533,7 +533,7 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
{
struct usb_host_config *config = dev->actconfig;
int err;
- u8 bootresponse[12];
+ u8 bootresponse[0x12];
int fwsize;
int count;
@@ -863,13 +863,14 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
ep->skip_packets = 4;
/*
- * M-Audio Fast Track C400 - when packets are not skipped, real world
- * latency varies by approx. +/- 50 frames (at 96KHz) each time the
- * stream is (re)started. When skipping packets 16 at endpoint start
- * up, the real world latency is stable within +/- 1 frame (also
+ * M-Audio Fast Track C400/C600 - when packets are not skipped, real
+ * world latency varies by approx. +/- 50 frames (at 96KHz) each time
+ * the stream is (re)started. When skipping packets 16 at endpoint
+ * start up, the real world latency is stable within +/- 1 frame (also
* across power cycles).
*/
- if (ep->chip->usb_id == USB_ID(0x0763, 0x2030) &&
+ if ((ep->chip->usb_id == USB_ID(0x0763, 0x2030) ||
+ ep->chip->usb_id == USB_ID(0x0763, 0x2031)) &&
ep->type == SND_USB_ENDPOINT_TYPE_DATA)
ep->skip_packets = 16;
}