[alsa-devel] [PATCH 0/5] Alsa: snd-usb: Improve M-Audio Fast Track Ultra mixer - v3
This is the third try on a series of patches that improves the mixer for Fast Track Ultra (8R) devices by
* adding TLV to existing controls * adding new controls for the effect section.
In addition, it unifies the control creation for FTU and Ebox-44 devices.
Mark, could you please look at mixer_quirks.c. Do we really need the range settings in snd_create_std_mono_ctl()? BTW, you might like to add some TLV callback to the Ebox-44 controls as well.
I hope I really sorted Takashis issues out this time.
Regards,
Felix
Felix Homann (5): Unify M-Audio Fast Track Ultra and Ebox-44 mixer quirks. Rename and export mixer_vol_tlv Add TLV to M-Audio Fast Track Ultra controls Rename Fast Track Ultra mixer quirk functions M-Audio Fast Track Ultra: Add effect controls
sound/usb/mixer.c | 22 ++- sound/usb/mixer.h | 3 + sound/usb/mixer_quirks.c | 471 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 428 insertions(+), 68 deletions(-)
Merge snd_maudio_ftu_create_ctl() and snd_ebox44_create_ctl() into snd_create_std_mono_ctl(). As opposed to the ftu and ebox-44 specific functions, a TLV callback can be specified for controls created by snd_create_std_mono_ctl().
Signed-off-by: Felix Homann linuxaudio@showlabor.de
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e2072ed..d677e03 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -42,6 +42,85 @@
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+/* private_free callback */ +static void usb_mixer_elem_free(struct snd_kcontrol *kctl) +{ + kfree(kctl->private_data); + kctl->private_data = NULL; +} + +/* This function allows for the creation of standard UAC controls. + * See the quirks for M-Audio FTUs or Ebox-44. + * If you don't want to set a TLV callback pass NULL. + * + * Since there doesn't seem to be a devices that needs a multichannel + * version, we keep it mono for simplicity. + */ +static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, + unsigned int unitid, + 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; + + cval = kzalloc(sizeof(*cval), GFP_KERNEL); + if (!cval) + return -ENOMEM; + + cval->id = unitid; + cval->mixer = mixer; + cval->val_type = val_type; + cval->channels = 1; + cval->control = control; + cval->cmask = cmask; + + /* FIXME: Do we need this? + * The following values are for compatibility with + * Ebox-44 mixer. + * But the corresponding ebox-44 function says: + * "Volume controls will override these values" + * + * These values don't have any effect at all for + * M-Audio FTUs. + * So I think, we can safely omit the range settings here. + */ + cval->min = 0; + cval->max = 1; + cval->res = 0; + cval->dBmin = 0; + cval->dBmax = 0; + + /* 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; + + /* set TLV */ + if (tlv_callback) { + 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; +} + /* * Sound Blaster remote control configuration * @@ -496,59 +575,37 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
/* M-Audio FastTrack Ultra quirks */
-/* private_free callback */ -static void usb_mixer_elem_free(struct snd_kcontrol *kctl) -{ - kfree(kctl->private_data); - kctl->private_data = NULL; -} - -static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer, - int in, int out, const char *name) -{ - struct usb_mixer_elem_info *cval; - struct snd_kcontrol *kctl; - - cval = kzalloc(sizeof(*cval), GFP_KERNEL); - if (!cval) - return -ENOMEM; - - cval->id = 5; - cval->mixer = mixer; - cval->val_type = USB_MIXER_S16; - cval->channels = 1; - cval->control = out + 1; - cval->cmask = 1 << in; - - kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); - if (!kctl) { - kfree(cval); - return -ENOMEM; - } - - snprintf(kctl->id.name, sizeof(kctl->id.name), name); - kctl->private_free = usb_mixer_elem_free; - return snd_usb_mixer_add_control(mixer, kctl); -} - -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]; + unsigned int control, cmask; int in, out, err;
+ const unsigned int id = 5; + const int 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); + "AIn%d - Out%d Capture Volume", + in + 1, out + 1); + err = snd_create_std_mono_ctl(mixer, id, control, + cmask, val_type, name, + NULL); 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); + "DIn%d - Out%d Playback Volume", + in - 7, out + 1); + err = snd_create_std_mono_ctl(mixer, id, control, + cmask, val_type, name, + NULL); if (err < 0) return err; } @@ -557,44 +614,18 @@ static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) return 0; }
-static int snd_ebox44_create_ctl(struct usb_mixer_interface *mixer, - int unitid, int control, int cmask, - int val_type, const char *name) +static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) { - struct usb_mixer_elem_info *cval; - struct snd_kcontrol *kctl; - - cval = kzalloc(sizeof(*cval), GFP_KERNEL); - if (!cval) - return -ENOMEM; - - cval->id = unitid; - cval->mixer = mixer; - - cval->val_type = val_type; - cval->channels = 1; - cval->control = control; - cval->cmask = cmask; - - /* Volume controls will override these values */ - cval->min = 0; - cval->max = 1; - cval->res = 0; - - cval->dBmin = 0; - cval->dBmax = 0; + int err;
- kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); - if (!kctl) { - kfree(cval); - return -ENOMEM; - } + err = snd_maudio_ftu_create_volume_ctls(mixer); + if (err < 0) + return err;
- snprintf(kctl->id.name, sizeof(kctl->id.name), name); - kctl->private_free = usb_mixer_elem_free; - return snd_usb_mixer_add_control(mixer, kctl); + return 0; }
+ /* * Create mixer for Electrix Ebox-44 * @@ -605,17 +636,26 @@ static int snd_ebox44_create_ctl(struct usb_mixer_interface *mixer,
static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer) { - snd_ebox44_create_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN, "Headphone Playback Switch"); - snd_ebox44_create_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16, "Headphone A Mix Playback Volume"); - snd_ebox44_create_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16, "Headphone B Mix Playback Volume"); - - snd_ebox44_create_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN, "Output Playback Switch"); - snd_ebox44_create_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16, "Output A Playback Volume"); - snd_ebox44_create_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16, "Output B Playback Volume"); - - snd_ebox44_create_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN, "Input Capture Switch"); - snd_ebox44_create_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16, "Input A Capture Volume"); - snd_ebox44_create_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16, "Input B Capture Volume"); + snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN, + "Headphone Playback Switch", NULL); + snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16, + "Headphone A Mix Playback Volume", NULL); + snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16, + "Headphone B Mix Playback Volume", NULL); + + snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN, + "Output Playback Switch", NULL); + snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16, + "Output A Playback Volume", NULL); + snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16, + "Output B Playback Volume", NULL); + + snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN, + "Input Capture Switch", NULL); + snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16, + "Input A Capture Volume", NULL); + snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16, + "Input B Capture Volume", NULL);
return 0; }
On Mon, 23 Apr 2012, Felix Homann wrote:
+/* This function allows for the creation of standard UAC controls.
- See the quirks for M-Audio FTUs or Ebox-44.
- If you don't want to set a TLV callback pass NULL.
- Since there doesn't seem to be a devices that needs a multichannel
- version, we keep it mono for simplicity.
- */
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
unsigned int unitid,
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;
- cval = kzalloc(sizeof(*cval), GFP_KERNEL);
- if (!cval)
return -ENOMEM;
- cval->id = unitid;
- cval->mixer = mixer;
- cval->val_type = val_type;
- cval->channels = 1;
- cval->control = control;
- cval->cmask = cmask;
- /* FIXME: Do we need this?
* The following values are for compatibility with
* Ebox-44 mixer.
* But the corresponding ebox-44 function says:
* "Volume controls will override these values"
*
* These values don't have any effect at all for
* M-Audio FTUs.
* So I think, we can safely omit the range settings here.
*/
- cval->min = 0;
- cval->max = 1;
- cval->res = 0;
- cval->dBmin = 0;
- cval->dBmax = 0;
When implementing the Ebox44 quirk, I found I needed this. The min and max would be automatically completed for the S16 values, but not for the mute buttons, so I defaulted to the range required for the BOOLEAN.
I was really hoping some one would explain this when I RFC'd the patch. But at that time the code was not part of some general-purpose function so it wasn't really an issue.
Hi Mark,
2012/4/23 Mark Hills mark@pogo.org.uk:
When implementing the Ebox44 quirk, I found I needed this. The min and max would be automatically completed for the S16 values, but not for the mute buttons, so I defaulted to the range required for the BOOLEAN.
thanks for answering and sorry for my cc'ing you in so many iterations of my patch set. We leave it as it is then until someone has a need for other defaults.
Regards,
Felix
At Mon, 23 Apr 2012 19:36:06 +0100 (BST), Mark Hills wrote:
On Mon, 23 Apr 2012, Felix Homann wrote:
+/* This function allows for the creation of standard UAC controls.
- See the quirks for M-Audio FTUs or Ebox-44.
- If you don't want to set a TLV callback pass NULL.
- Since there doesn't seem to be a devices that needs a multichannel
- version, we keep it mono for simplicity.
- */
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
unsigned int unitid,
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;
- cval = kzalloc(sizeof(*cval), GFP_KERNEL);
- if (!cval)
return -ENOMEM;
- cval->id = unitid;
- cval->mixer = mixer;
- cval->val_type = val_type;
- cval->channels = 1;
- cval->control = control;
- cval->cmask = cmask;
- /* FIXME: Do we need this?
* The following values are for compatibility with
* Ebox-44 mixer.
* But the corresponding ebox-44 function says:
* "Volume controls will override these values"
*
* These values don't have any effect at all for
* M-Audio FTUs.
* So I think, we can safely omit the range settings here.
*/
- cval->min = 0;
- cval->max = 1;
- cval->res = 0;
- cval->dBmin = 0;
- cval->dBmax = 0;
When implementing the Ebox44 quirk, I found I needed this. The min and max would be automatically completed for the S16 values, but not for the mute buttons, so I defaulted to the range required for the BOOLEAN.
I was really hoping some one would explain this when I RFC'd the patch. But at that time the code was not part of some general-purpose function so it wasn't really an issue.
The reason is because get_min_max*() isn't called in the place you created these controls, and get_min_max() would be called only for integer volumes later even if uninitialized. A short cut for booleans.
Takashi
Rename mixer_vol_tlv to snd_usb_mixer_vol_tlv and export it to make it reuseable in mixer_quirks.c.
Signed-off-by: Felix Homann linuxaudio@showlabor.de
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c374c72..bb56f53 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -486,7 +486,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, /* * TLV callback for mixer volume controls */ -static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, +int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { struct usb_mixer_elem_info *cval = kcontrol->private_data; @@ -1158,7 +1158,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, if (control == UAC_FU_VOLUME) { check_mapped_dB(map, cval); if (cval->dBmin < cval->dBmax || !cval->initialized) { - kctl->tlv.c = mixer_vol_tlv; + kctl->tlv.c = snd_usb_mixer_vol_tlv; kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 81b2d8a..a7f3d45 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -68,4 +68,7 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl);
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *_tlv); + #endif /* __USBMIXER_H */
This adds db gain information to M-Audio Fast Track Ultra (8R) devices.
Signed-off-by: Felix Homann linuxaudio@showlabor.de
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index d677e03..9f1987f 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -594,7 +594,7 @@ static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) in + 1, out + 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, name, - NULL); + &snd_usb_mixer_vol_tlv); if (err < 0) return err; } @@ -605,7 +605,7 @@ static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) in - 7, out + 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, name, - NULL); + &snd_usb_mixer_vol_tlv); if (err < 0) return err; }
This is in preparation for more FTU controls to come. Should help keeping names a bit shorter.
Signed-off-by: Felix Homann linuxaudio@showlabor.de
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 9f1987f..534e81e 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -575,8 +575,8 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
/* M-Audio FastTrack Ultra quirks */
-/* Create a volume control for FTU devices*/ -static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) +/* Create volume controls for FTU devices*/ +static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) { char name[64]; unsigned int control, cmask; @@ -614,11 +614,11 @@ static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) return 0; }
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) +static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) { int err;
- err = snd_maudio_ftu_create_volume_ctls(mixer); + err = snd_ftu_create_volume_ctls(mixer); if (err < 0) return err;
@@ -703,7 +703,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ - err = snd_maudio_ftu_create_mixer(mixer); + err = snd_ftu_create_mixer(mixer); break;
case USB_ID(0x0b05, 0x1739):
This adds controls for the effects section on the FTU devices. Some of these controls need volume quirks. They are added to mixer.c.
Signed-off-by: Felix Homann linuxaudio@showlabor.de
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bb56f53..195b6d2 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -770,6 +770,24 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { switch (cval->mixer->chip->usb_id) { + 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 + "usb-audio: 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 + "usb-audio: 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): diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 534e81e..21f2519 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -574,6 +574,186 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, }
/* M-Audio FastTrack Ultra quirks */ +/* FTU Effect switch */ +struct snd_ftu_eff_switch_priv_val { + struct usb_mixer_interface *mixer; + int cached_value; + int is_cached; +}; + +static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const 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_ftu_eff_switch_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_usb_audio *chip; + struct usb_mixer_interface *mixer; + struct snd_ftu_eff_switch_priv_val *pval; + int err; + unsigned char value[2]; + + const int id = 6; + const int validx = 1; + const int val_len = 2; + + value[0] = 0x00; + value[1] = 0x00; + + pval = (struct snd_ftu_eff_switch_priv_val *) + 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 (snd_BUG_ON(!mixer)) + return -EINVAL; + + chip = (struct snd_usb_audio *) mixer->chip; + if (snd_BUG_ON(!chip)) + return -EINVAL; + + + 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 err; + + ucontrol->value.enumerated.item[0] = value[0]; + pval->cached_value = value[0]; + pval->is_cached = 1; + + return 0; +} + +static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_usb_audio *chip; + struct snd_ftu_eff_switch_priv_val *pval; + + struct usb_mixer_interface *mixer; + int changed, cur_val, err, new_val; + unsigned char value[2]; + + + const int id = 6; + const int validx = 1; + const int val_len = 2; + + changed = 0; + + pval = (struct snd_ftu_eff_switch_priv_val *) + kctl->private_value; + cur_val = pval->cached_value; + new_val = ucontrol->value.enumerated.item[0]; + + mixer = (struct usb_mixer_interface *) pval->mixer; + if (snd_BUG_ON(!mixer)) + return -EINVAL; + + chip = (struct snd_usb_audio *) mixer->chip; + if (snd_BUG_ON(!chip)) + return -EINVAL; + + 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 err; + + 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 err; + + pval->cached_value = new_val; + pval->is_cached = 1; + changed = 1; + } + + return changed; +} + +static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) +{ + static 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_ftu_eff_switch_info, + .get = snd_ftu_eff_switch_get, + .put = snd_ftu_eff_switch_put + }; + + int err; + struct snd_kcontrol *kctl; + struct snd_ftu_eff_switch_priv_val *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; +}
/* Create volume controls for FTU devices*/ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) @@ -614,6 +794,102 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) return 0; }
+/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Volume"; + const unsigned int id = 6; + const int val_type = USB_MIXER_U8; + const unsigned int control = 2; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Duration"; + const unsigned int id = 6; + const int val_type = USB_MIXER_S16; + const unsigned int control = 3; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) +{ + static const char name[] = "Effect Feedback Volume"; + const unsigned int id = 6; + const int val_type = USB_MIXER_U8; + const unsigned int control = 4; + const unsigned int cmask = 0; + + return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, + name, NULL); +} + +static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) +{ + unsigned int cmask; + int err, ch; + char name[48]; + + const unsigned int id = 7; + const int val_type = USB_MIXER_S16; + const unsigned int control = 7; + + for (ch = 0; ch < 4; ++ch) { + cmask = 1 << ch; + snprintf(name, sizeof(name), + "Effect Return %d Volume", ch + 1); + err = snd_create_std_mono_ctl(mixer, id, control, + cmask, val_type, name, + snd_usb_mixer_vol_tlv); + if (err < 0) + return err; + } + + return 0; +} + +static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) +{ + unsigned int cmask; + int err, ch; + char name[48]; + + const unsigned int id = 5; + const int val_type = USB_MIXER_S16; + const unsigned int control = 9; + + for (ch = 0; ch < 8; ++ch) { + cmask = 1 << ch; + snprintf(name, sizeof(name), + "Effect Send AIn%d Volume", ch + 1); + err = snd_create_std_mono_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_create_std_mono_ctl(mixer, id, control, cmask, + val_type, name, + snd_usb_mixer_vol_tlv); + if (err < 0) + return err; + } + return 0; +} + static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) { int err; @@ -622,6 +898,29 @@ static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) if (err < 0) return err;
+ err = snd_ftu_create_effect_switch(mixer); + if (err < 0) + return err; + err = snd_ftu_create_effect_volume_ctl(mixer); + if (err < 0) + return err; + + err = snd_ftu_create_effect_duration_ctl(mixer); + if (err < 0) + return err; + + err = snd_ftu_create_effect_feedback_ctl(mixer); + if (err < 0) + return err; + + err = snd_ftu_create_effect_return_ctls(mixer); + if (err < 0) + return err; + + err = snd_ftu_create_effect_send_ctls(mixer); + if (err < 0) + return err; + return 0; }
On Mon, 23 Apr 2012, Felix Homann wrote:
[...]
BTW, you might like to add some TLV callback to the Ebox-44 controls as well.
I can, but I'll need some assistance or documentation to explain how. I took a quick look, and it wasn't very clear.
I presume this adds dB values to the mixer? Unless I have taken some measurements is it not better to leave them unassigned than add bogus values?
Thanks
2012/4/23 Mark Hills mark@pogo.org.uk:
I can, but I'll need some assistance or documentation to explain how. I took a quick look, and it wasn't very clear.
I presume this adds dB values to the mixer? Unless I have taken some measurements is it not better to leave them unassigned than add bogus values?
Yes, measurements would be great but I haven't done any measurements on the FTUs either.
The TLV callbacks I've added to the volume controls enhances the usability of the controls anyway. Without the TLV callbacks I would have to go to at least 90% in amixer etc. to hear anythin at all. With TLV callbacks I can hear a difference all over the control range.
(Chances are, that the returned dB gain values are correct since the devices opeerate nearly standard conform.)
Just try with your S16 controls like I did for the FTUs and see if it makes a difference for you.
Regards,
Felix
At Mon, 23 Apr 2012 20:24:22 +0200, Felix Homann wrote:
This is the third try on a series of patches that improves the mixer for Fast Track Ultra (8R) devices by
* adding TLV to existing controls * adding new controls for the effect section.
In addition, it unifies the control creation for FTU and Ebox-44 devices.
Mark, could you please look at mixer_quirks.c. Do we really need the range settings in snd_create_std_mono_ctl()? BTW, you might like to add some TLV callback to the Ebox-44 controls as well.
I hope I really sorted Takashis issues out this time.
I applied the patches with some monior fixes now. Thanks!
Takashi
Regards,
Felix
Felix Homann (5): Unify M-Audio Fast Track Ultra and Ebox-44 mixer quirks. Rename and export mixer_vol_tlv Add TLV to M-Audio Fast Track Ultra controls Rename Fast Track Ultra mixer quirk functions M-Audio Fast Track Ultra: Add effect controls
sound/usb/mixer.c | 22 ++- sound/usb/mixer.h | 3 + sound/usb/mixer_quirks.c | 471 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 428 insertions(+), 68 deletions(-)
-- 1.7.5.4
2012/4/24 Takashi Iwai tiwai@suse.de:
I applied the patches with some monior fixes now. Thanks!
Thank you!
Felix
participants (3)
-
Felix Homann
-
Mark Hills
-
Takashi Iwai