[alsa-devel] [PATCH - Add mixer support for M-Audio FTU series 1/1]Add basic mixer support for M-Audio FTU (8R)

linuxaudio at showlabor.de linuxaudio at showlabor.de
Sat Sep 25 08:36:44 CEST 2010


From: Felix Homann <linuxaudio at showlabor.de>


Signed-off-by: Felix Homann <linuxaudio at showlabor.de>

diff --git a/usb/card.c b/usb/card.c
index 800f7cb..28efd7b 100644
--- a/usb/card.c
+++ b/usb/card.c
@@ -489,6 +489,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
 	if (!chip->ctrl_intf)
 		chip->ctrl_intf = alts;
 
+	/* try to create a mixer for quirked devices, too */
+	if (snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
+		goto __error;
+	}
+
 	if (err > 0) {
 		/* create normal USB audio interfaces */
 		if (snd_usb_create_streams(chip, ifnum) < 0 ||
diff --git a/usb/mixer.c b/usb/mixer.c
index 3ed3901..edb9893 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -85,16 +85,6 @@ struct mixer_build {
 	const struct usbmix_selector_map *selector_map;
 };
 
-enum {
-	USB_MIXER_BOOLEAN,
-	USB_MIXER_INV_BOOLEAN,
-	USB_MIXER_S8,
-	USB_MIXER_U8,
-	USB_MIXER_S16,
-	USB_MIXER_U16,
-};
-
-
 /*E-mu 0202(0404) eXtension Unit(XU) control*/
 enum {
 	USB_XU_CLOCK_RATE 		= 0xe301,
@@ -2149,6 +2139,71 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
 	return 0;
 }
 
+/* This is just the same as 'add_control_to_empty' but using a mixer instead of a mixer_build */
+int add_unique_control_to_empty_mixer(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl)
+{
+	struct usb_mixer_elem_info *cval = kctl->private_data;
+	int err;
+
+	/* No duplicates! */
+	if (snd_ctl_find_id(mixer->chip->card, &kctl->id))
+		return 0;
+
+	if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
+		snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
+		return err;
+	}
+
+	cval->elem_id = &kctl->id;
+	cval->next_id_elem = mixer->id_elems[cval->id];
+	mixer->id_elems[cval->id] = cval;
+
+	return 0;
+}
+
+int build_named_mixer_unit_ctl(struct usb_mixer_interface *mixer,
+	int in_pin, int in_ch, int unitid, int val_type, unsigned int cmask, char *ctrl_name, int channels)
+{
+	struct usb_mixer_elem_info *cval;
+	struct snd_kcontrol *kctl;
+	int err;
+
+	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+	if (!cval)
+		return -1;
+
+	cval->mixer = mixer;
+	cval->id = unitid;
+	cval->control = in_ch + 1; /* based on 1 */
+	cval->val_type = val_type; /* like USB_MIXER_S16 etc. */
+	if (!((0 < channels) && (channels <= MAX_CHANNELS)))
+		return -1;
+	cval->channels = 1;
+	cval->cmask = cmask;
+	/* get min/max values */
+	get_min_max(cval, 0);
+
+	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
+	if (!kctl) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+		kfree(cval);
+		return -1;
+	}
+
+	kctl->tlv.c = mixer_vol_tlv;
+	kctl->vd[0].access |=
+		SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	kctl->private_free = usb_mixer_elem_free;
+
+	sprintf(kctl->id.name, ctrl_name);
+
+	if (err = add_unique_control_to_empty_mixer(mixer, kctl))
+		return err;
+
+	return 0;
+}
+
 int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
 			 int ignore_error)
 {
diff --git a/usb/mixer.h b/usb/mixer.h
index 26c636c..f7378c5 100644
--- a/usb/mixer.h
+++ b/usb/mixer.h
@@ -24,7 +24,16 @@ struct usb_mixer_interface {
 	u8 xonar_u1_status;
 };
 
-#define MAX_CHANNELS	10	/* max logical channels */
+#define MAX_CHANNELS	16	/* max logical channels */
+
+enum {
+	USB_MIXER_BOOLEAN,
+	USB_MIXER_INV_BOOLEAN,
+	USB_MIXER_S8,
+	USB_MIXER_U8,
+	USB_MIXER_S16,
+	USB_MIXER_U16,
+};
 
 struct usb_mixer_elem_info {
 	struct usb_mixer_interface *mixer;
@@ -53,4 +62,7 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
 int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
 				int request, int validx, int value_set);
 
+int build_named_mixer_unit_ctl(struct usb_mixer_interface *mixer,
+		int in_pin, int in_ch, int unitid, int val_type, unsigned int cmask,
+		char* ctrl_name, int channels);
 #endif /* __USBMIXER_H */
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index e7df1e5..7843451 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -354,6 +354,32 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 	}
 }
 
+int snd_ftu_controls_create(struct usb_mixer_interface *mixer)
+{
+	char name[44];
+	int out, in_ch, unitid, err;
+	unsigned int cmask;
+	int val_type =  USB_MIXER_S16;
+	int channels = 1;
+	unitid = 5; // FTU's unit id
+
+	for (out = 0; out < 8; ++out) {
+		for (in_ch = 0; in_ch < 16; ++in_ch) {
+				cmask = (1 << in_ch);
+			if (in_ch < 8)
+				sprintf(name, "AIn%d - Out%d Capture Volume", in_ch + 1, out + 1);
+			else if (in_ch >= 8)
+				sprintf(name, "DIn%d - Out%d Playback Volume", in_ch - 7, out + 1);     
+			if ((err = build_named_mixer_unit_ctl(mixer, in_ch, out, unitid, 
+				val_type, cmask, name, channels))) {
+				return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
 int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 {
 	int err;
@@ -379,6 +405,14 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	/* M-Audio Fast Track Ultra (8R) */
+	if (mixer->chip->usb_id == USB_ID(0x0763, 0x2080) ||
+	    mixer->chip->usb_id == USB_ID(0x0763, 0x2081)) {
+		err = snd_ftu_controls_create(mixer);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
diff --git a/usb/usbmixer.h b/usb/usbmixer.h
index 63101ae..0ddbeab 100644
--- a/usb/usbmixer.h
+++ b/usb/usbmixer.h
@@ -22,7 +22,7 @@ struct usb_mixer_interface {
 	u8 xonar_u1_status;
 };
 
-#define MAX_CHANNELS	10	/* max logical channels */
+#define MAX_CHANNELS	16	/* max logical channels */
 
 struct usb_mixer_elem_info {
 	struct usb_mixer_interface *mixer;
-- 
1.7.1



More information about the Alsa-devel mailing list