diff --git a/usb/mixer.c b/usb/mixer.c
index ab23869..8d11dd9 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -501,6 +501,11 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	return 0;
 }
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * reuse it in mixer_quirks.c */
+int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv) = &mixer_vol_tlv;
+
 /*
  * parser routines begin here...
  */
@@ -770,7 +775,25 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
 				  struct snd_kcontrol *kctl)
 {
 	switch (cval->mixer->chip->usb_id) {
-	case USB_ID(0x0471, 0x0101):
+	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
+	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
+		if ( (strcmp(kctl->id.name, "Effect Duration") == 0)) {
+			snd_printk(KERN_INFO
+				"set quirk for FTU Effect Duration\n");
+			cval->min = 0x0000;
+			cval->max = 0x7f00;
+			cval->res = 0x0100;
+			break;
+		}
+		if ( (strcmp(kctl->id.name, "Effect Volume") == 0) |
+			(strcmp(kctl->id.name, "Effect Feedback Volume") == 0) ) {
+			snd_printk(KERN_INFO
+				"set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+       	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
 	case USB_ID(0x0672, 0x1041):
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index ab125ee..97582ad 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -34,6 +34,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -41,6 +42,8 @@
 #include "helper.h"
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+extern int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv);
 
 /*
  * Sound Blaster remote control configuration
@@ -496,6 +499,12 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 
+/* Note: Some of the FTU controls need volume control quirks
+ * If you change the naming scheme of the controls you need
+ * to change the corresponding names in volume_control_quirks() 
+ * in mixer.c as well
+ */
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -503,56 +512,409 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 	kctl->private_data = NULL;
 }
 
+struct snd_maudio_ftu_effect_switch_private_value {
+	struct usb_mixer_interface *mixer;
+	int cached_value;
+	int is_cached;
+};
+
+
+static int snd_maudio_ftu_effect_switch_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[8] = {"Room 1",
+			  "Room 2",
+			  "Room 3",
+			  "Hall 1",
+			  "Hall 2",
+			  "Plate",
+			  "Delay",
+			  "Echo"
+	};
+	
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 8;
+	if (uinfo->value.enumerated.item > 7)
+		uinfo->value.enumerated.item = 7;
+	strcpy(uinfo->value.enumerated.name,
+		texts[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_maudio_ftu_effect_switch_get(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct usb_mixer_interface *mixer;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+	int err, id, validx, val_len, val_type;
+	unsigned char value[2];
+
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) kctl->private_value;
+
+	if (pval->is_cached) {
+		ucontrol->value.enumerated.item[0] = pval->cached_value;
+		return 0;
+	}
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	value[0] = 0x00;
+	value[1] = 0x00;
+
+	val_len = 2;
+
+	err = snd_usb_ctl_msg(chip->dev,
+			usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+			validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+			value, val_len);
+	if (err < 0)
+		return -1;
+
+	ucontrol->value.enumerated.item[0] = value[0];
+	pval->cached_value = value[0];
+	pval->is_cached = 1;
+
+       	return 0;
+}
+
+static int snd_maudio_ftu_effect_switch_put(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+
+	struct usb_mixer_interface *mixer;
+	int  changed, cur_val, err, id, new_val, validx, val_len, val_type;
+	unsigned char value[2];
+
+	changed = 0;
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	val_len = 2;
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) kctl->private_value; 
+	cur_val = pval->cached_value;
+	new_val = ucontrol->value.enumerated.item[0];
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+	
+	if (!pval->is_cached) {
+		/* Read current value */
+		err = snd_usb_ctl_msg(chip->dev,
+				usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+				value, val_len);
+		if (err < 0)
+			return -1;
+
+		cur_val = value[0];
+		pval->cached_value = cur_val;
+		pval->is_cached = 1;
+	}
+	/* update value if needed */
+	if (cur_val != new_val) {
+		value[0] = new_val;
+		value[1] = 0;
+		err = snd_usb_ctl_msg(chip->dev,
+				usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+				value, val_len);
+		if (err < 0)
+			return -1;
+
+		pval->cached_value = new_val;
+		pval->is_cached = 1;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int snd_maudio_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+	struct snd_kcontrol_new template = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Effect Program Switch",
+		.index = 0,
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = snd_maudio_ftu_effect_switch_info,
+		.get = snd_maudio_ftu_effect_switch_get,
+		.put = snd_maudio_ftu_effect_switch_put
+	};
+	
+	int err;
+	struct snd_kcontrol *kctl;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+
+	pval = kzalloc(sizeof(*pval), GFP_KERNEL);
+	if (!pval)
+		return -ENOMEM;
+
+	pval->cached_value = 0;
+	pval->is_cached = 0;
+	pval->mixer = mixer;
+
+	template.private_value = (unsigned long) pval;
+	kctl = snd_ctl_new1(&template, mixer->chip);
+	if (!kctl) {
+		kfree(pval);
+		return -ENOMEM;
+	}
+
+	err = snd_ctl_add(mixer->chip->card, kctl);
+	if (err < 0)
+		return err;
+	
+	return 0;
+}
+
 static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+				unsigned int id,
+				unsigned int control,
+				unsigned int cmask,
+				int val_type,
+				const char *name,
+				snd_kcontrol_tlv_rw_t *tlv_callback)
 {
+	int err;
 	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+ 	struct snd_kcontrol *kctl;
 
 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
 	if (!cval)
 		return -ENOMEM;
 
-	cval->id = 5;
+	cval->id = id;
 	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
+	cval->val_type = val_type;
 	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
-
+	cval->control = control;
+	cval->cmask = cmask;
+		
+	
+	/* Create control */
 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
 	if (!kctl) {
 		kfree(cval);
 		return -ENOMEM;
 	}
-
+	
+	/* Set name */
 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
 	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	
+	/* set TLV */
+	if (tlv_callback != NULL) { 
+		kctl->tlv.c = tlv_callback;
+		kctl->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	/* Add control to mixer */
+	err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create a volume control for FTU devices*/
+static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
-	int in, out, err;
+	unsigned int id, control, cmask;
+	int in, out, err, val_type;
+
+	id = 5;
+	val_type = USB_MIXER_S16;
 
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
 	}
+	
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 2;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Duration";
+
+	id = 6;
+	val_type = USB_MIXER_S16;
+	control = 3;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Feedback Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 4;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, NULL);
+}
+
+static int snd_maudio_ftu_create_effects_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 7;
+	val_type = USB_MIXER_S16;
+	control = 2;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d Volume", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effects_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 5;
+	val_type = USB_MIXER_S16;
+	control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d Volume", ch + 1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	for (ch = 8; ch < 16; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send DIn%d Volume", ch - 7);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_maudio_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+	
+	err = snd_maudio_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_send_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_switch(mixer);
+	if (err < 0)
+		return err;
+
+	/* err = snd_maudio_ftu_create_test_switch(mixer); */
+	/* if (err < 0) */
+	/* 	return err; */
 
 	return 0;
 }
