}
+/* release elem->private_free as well; called only once for each *_store */
+static void elem_private_free(struct snd_kcontrol *kctl)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ if (elem)
+ kfree(elem->private_data);
+ kfree(elem);
+ kctl->private_data = NULL;
+}
+
static int add_new_ctl(struct usb_mixer_interface *mixer,
const struct snd_kcontrol_new *ncontrol,
int index, int val_type, int channels,
const char *name, const void *opt,
- void (*freeer)(struct snd_kcontrol *kctl),
+ bool do_private_free,
struct usb_mixer_elem_info **elem_ret)
{
struct snd_kcontrol *kctl;
return -ENOMEM;
}
- kctl->private_free = freeer;
+ if (do_private_free)
+ kctl->private_free = elem_private_free;
+ else
+ kctl->private_free = snd_usb_mixer_elem_free;
strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "EQ Switch",
- .freeer = snd_usb_mixer_elem_free
},
{ /* EQ low gain */
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ Low Volume",
- .freeer = snd_usb_mixer_elem_free
},
{ /* EQ low freq */
.kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ Low Frequence",
- .freeer = NULL
},
{ /* EQ mid low gain */
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidLow Volume",
- .freeer = snd_usb_mixer_elem_free
},
{ /* EQ mid low freq */
.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidLow Frequence",
- .freeer = NULL
},
{ /* EQ mid low Q */
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidQLow Q",
- .freeer = NULL
},
{ /* EQ mid high gain */
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidHigh Volume",
- .freeer = snd_usb_mixer_elem_free
},
{ /* EQ mid high freq */
.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidHigh Frequence",
- .freeer = NULL
},
{ /* EQ mid high Q */
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ MidHigh Q",
- .freeer = NULL
},
{ /* EQ high gain */
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ High Volume",
- .freeer = snd_usb_mixer_elem_free
},
{ /* EQ low freq */
.kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "EQ High Frequence",
- .freeer = NULL
},
};
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "Compressor Switch",
- .freeer = snd_usb_mixer_elem_free
},
{ /* Comp threshold */
.kcontrol_new = &snd_us16x08_comp_threshold_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Compressor Threshold Volume",
- .freeer = NULL
},
{ /* Comp ratio */
.kcontrol_new = &snd_us16x08_comp_ratio_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Compressor Ratio",
- .freeer = NULL
},
{ /* Comp attack */
.kcontrol_new = &snd_us16x08_comp_attack_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Compressor Attack",
- .freeer = NULL
},
{ /* Comp release */
.kcontrol_new = &snd_us16x08_comp_release_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Compressor Release",
- .freeer = NULL
},
{ /* Comp gain */
.kcontrol_new = &snd_us16x08_comp_gain_ctl,
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Compressor Volume",
- .freeer = NULL
},
};
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "Phase Switch",
- .freeer = snd_usb_mixer_elem_free,
.default_val = 0
},
{ /* Fader */
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Line Volume",
- .freeer = NULL,
.default_val = 127
},
{ /* Mute */
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "Mute Switch",
- .freeer = NULL,
.default_val = 0
},
{ /* Pan */
.type = USB_MIXER_U16,
.num_channels = 16,
.name = "Pan Left-Right Volume",
- .freeer = NULL,
.default_val = 127
},
};
.type = USB_MIXER_U8,
.num_channels = 16,
.name = "Master Volume",
- .freeer = NULL,
.default_val = 127
},
{ /* Bypass */
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "DSP Bypass Switch",
- .freeer = NULL,
.default_val = 0
},
{ /* Buss out */
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "Buss Out Switch",
- .freeer = NULL,
.default_val = 0
},
{ /* Master mute */
.type = USB_MIXER_BOOLEAN,
.num_channels = 16,
.name = "Master Mute Switch",
- .freeer = NULL,
.default_val = 0
},
/* just check for non-MIDI interface */
if (mixer->hostif->desc.bInterfaceNumber == 3) {
- /* create compressor mixer elements */
- comp_store = snd_us16x08_create_comp_store();
- if (comp_store == NULL)
- return -ENOMEM;
-
- /* create eq store */
- eq_store = snd_us16x08_create_eq_store();
- if (eq_store == NULL) {
- kfree(comp_store);
- return -ENOMEM;
- }
-
- /* create meters store */
- meter_store = snd_us16x08_create_meter_store();
- if (meter_store == NULL) {
- kfree(comp_store);
- kfree(eq_store);
- return -ENOMEM;
- }
-
/* add routing control */
err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
- NULL, NULL, &elem);
+ NULL, false, &elem);
if (err < 0) {
usb_audio_dbg(mixer->chip,
"Failed to create route control, err:%d\n",
elem->cache_val[i] = i < 2 ? i : i + 2;
elem->cached = 0xff;
+ /* create compressor mixer elements */
+ comp_store = snd_us16x08_create_comp_store();
+ if (!comp_store)
+ return -ENOMEM;
+
/* add master controls */
for (i = 0;
i < sizeof(master_controls)
master_controls[i].num_channels,
master_controls[i].name,
comp_store,
- master_controls[i].freeer, &elem);
+ i == 0, /* release comp_store only once */
+ &elem);
if (err < 0)
return err;
elem->cache_val[0] = master_controls[i].default_val;
channel_controls[i].num_channels,
channel_controls[i].name,
comp_store,
- channel_controls[i].freeer, &elem);
+ false, &elem);
if (err < 0)
return err;
for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
elem->cached = 0xffff;
}
+ /* create eq store */
+ eq_store = snd_us16x08_create_eq_store();
+ if (!eq_store)
+ return -ENOMEM;
+
/* add EQ controls */
for (i = 0; i < sizeof(eq_controls) /
sizeof(control_params); i++) {
eq_controls[i].num_channels,
eq_controls[i].name,
eq_store,
- eq_controls[i].freeer, NULL);
+ i == 0, /* release eq_store only once */
+ NULL);
if (err < 0)
return err;
}
comp_controls[i].num_channels,
comp_controls[i].name,
comp_store,
- comp_controls[i].freeer, NULL);
+ false, NULL);
if (err < 0)
return err;
}
+ /* create meters store */
+ meter_store = snd_us16x08_create_meter_store();
+ if (!meter_store)
+ return -ENOMEM;
+
/* meter function 'get' must access to compressor store
* so place a reference here
*/
meter_store->comp_store = comp_store;
err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
- (void *) meter_store, snd_usb_mixer_elem_free, NULL);
+ meter_store, true, NULL);
if (err < 0)
return err;
}