CRAS: alsa_io - Move volume curve to alsa output node

Currently if sound card doesn't have mixer control for 'Speaker', CRAS
won't associate the volume curve specified by [Speaker] label in card
config.
Fix this issue by moving volume curve from mixer control to alsa output
node.

BUG=chromium:682164
TEST=unittest. On platform without 'Speaker' control, verify volume
curve for speaker can be loaded.

Change-Id: I75411bf238f25f69ec383877df7278c7b7ff2949
Reviewed-on: https://chromium-review.googlesource.com/429813
Commit-Ready: Hsinyu Chao <hychao@chromium.org>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
diff --git a/cras/src/Makefile.am b/cras/src/Makefile.am
index 488dab5..d688bfb 100644
--- a/cras/src/Makefile.am
+++ b/cras/src/Makefile.am
@@ -443,7 +443,8 @@
 	server/cras_alsa_ucm_section.c \
 	server/cras_alsa_mixer_name.c
 alsa_io_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/server \
-	-I$(top_srcdir)/src/common
+	-I$(top_srcdir)/src/common \
+	-I$(top_srcdir)/src/server/config
 alsa_io_unittest_LDADD = -lgtest -lpthread
 
 alsa_jack_unittest_SOURCES = tests/alsa_jack_unittest.cc \
diff --git a/cras/src/server/cras_alsa_card.c b/cras/src/server/cras_alsa_card.c
index faea6a7..16a6ef5 100644
--- a/cras/src/server/cras_alsa_card.c
+++ b/cras/src/server/cras_alsa_card.c
@@ -116,6 +116,7 @@
 					   info->card_type,
 					   first,
 					   alsa_card->mixer,
+					   alsa_card->config,
 					   alsa_card->ucm,
 					   alsa_card->hctl,
 					   direction,
@@ -511,8 +512,7 @@
 	}
 
 	/* Create one mixer per card. */
-	alsa_card->mixer = cras_alsa_mixer_create(alsa_card->name,
-						  alsa_card->config);
+	alsa_card->mixer = cras_alsa_mixer_create(alsa_card->name);
 
 	if (alsa_card->mixer == NULL) {
 		syslog(LOG_ERR, "Fail opening mixer for %s.", alsa_card->name);
diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c
index a734d9d..6bb7e98 100644
--- a/cras/src/server/cras_alsa_io.c
+++ b/cras/src/server/cras_alsa_io.c
@@ -63,14 +63,13 @@
 /* This extends cras_ionode to include alsa-specific information.
  * Members:
  *    mixer_output - From cras_alsa_mixer.
- *    jack_curve - In absense of a mixer output, holds a volume curve to use
- *        when this jack is plugged.
- *    jack - The jack associated with the jack_curve (if it exists).
+ *    volume_curve - Volume curve for this node.
+ *    jack - The jack associated with the node.
  */
 struct alsa_output_node {
 	struct cras_ionode base;
 	struct mixer_control *mixer_output;
-	struct cras_volume_curve *jack_curve;
+	struct cras_volume_curve *volume_curve;
 	const struct cras_alsa_jack *jack;
 };
 
@@ -103,6 +102,7 @@
                           a possible action is to close/open device.
  * alsa_stream - Playback or capture type.
  * mixer - Alsa mixer used to control volume and mute of the device.
+ * config - Card config for this alsa device.
  * jack_list - List of alsa jack controls for this device.
  * ucm - CRAS use case manager, if configuration is found.
  * mmap_offset - offset returned from mmap_begin.
@@ -116,6 +116,8 @@
  *                   while hw_ptr keeps running ahead.
  * filled_zeros_for_draining - The number of zeros filled for draining.
  * severe_underrun_frames - The threshold for severe underrun.
+ * default_volume_curve - Default volume curve that converts from an index
+ *                        to dBFS.
  */
 struct alsa_io {
 	struct cras_iodev base;
@@ -133,6 +135,7 @@
 	unsigned int num_severe_underruns;
 	snd_pcm_stream_t alsa_stream;
 	struct cras_alsa_mixer *mixer;
+	const struct cras_card_config *config;
 	struct cras_alsa_jack_list *jack_list;
 	struct cras_use_case_mgr *ucm;
 	snd_pcm_uframes_t mmap_offset;
@@ -142,6 +145,7 @@
 	int is_free_running;
 	unsigned int filled_zeros_for_draining;
 	snd_pcm_uframes_t severe_underrun_frames;
+	struct cras_volume_curve *default_volume_curve;
 };
 
 static void init_device_settings(struct alsa_io *aio);
@@ -607,26 +611,16 @@
 	return (struct alsa_input_node *)aio->base.active_node;
 }
 
-/* Gets the curve for the active output node by below priority:
- * 1. Jack's volume curve.
- * 2. Output mixer control's volume curve.
- * 3. Card mixer's default volume curve.
+/* Gets the curve for the active output node. If the node doesn't have volume
+ * curve specified, return the default volume curve of the parent iodev.
  */
 static const struct cras_volume_curve *get_curve_for_output_node(
 		const struct alsa_io *aio,
 		const struct alsa_output_node *node)
 {
-	struct cras_volume_curve *curve = NULL;
-	if (node) {
-		if (node->jack_curve)
-			return node->jack_curve;
-
-		curve = cras_alsa_mixer_get_output_volume_curve(
-				node->mixer_output);
-		if (curve)
-			return curve;
-	}
-	return cras_alsa_mixer_default_volume_curve(aio->mixer);
+	if (node && node->volume_curve)
+		return node->volume_curve;
+	return aio->default_volume_curve;
 }
 
 /* Gets the curve for the active output. */
@@ -810,7 +804,7 @@
 	DL_FOREACH(aio->base.nodes, node) {
 		if (aio->base.direction == CRAS_STREAM_OUTPUT) {
 			aout = (struct alsa_output_node *)node;
-			cras_volume_curve_destroy(aout->jack_curve);
+			cras_volume_curve_destroy(aout->volume_curve);
 		}
 		cras_iodev_rm_node(&aio->base, node);
 		free(node->softvol_scalers);
@@ -1087,6 +1081,13 @@
 						   aio->base.info.stable_id_new
 						   );
 	output->mixer_output = cras_output;
+
+	/* Volume curve. */
+	output->volume_curve = cras_card_config_get_volume_curve_for_control(
+			aio->config,
+			name ? name
+			     : cras_alsa_mixer_get_control_name(cras_output));
+
 	strncpy(output->base.name, name, sizeof(output->base.name) - 1);
 	set_node_initial_state(&output->base, aio->card_type);
 	set_output_node_software_volume_needed(output, aio);
@@ -1277,7 +1278,7 @@
 
 /* Creates volume curve for the node associated with given jack. */
 static struct cras_volume_curve *create_volume_curve_for_jack(
-		const struct cras_alsa_mixer *mixer,
+		const struct cras_card_config *config,
 		const struct cras_alsa_jack *jack)
 {
 	struct cras_volume_curve *curve;
@@ -1285,13 +1286,13 @@
 
 	/* Use jack's UCM device name as key to get volume curve. */
 	name = cras_alsa_jack_get_ucm_device(jack);
-	curve = cras_alsa_mixer_create_volume_curve_for_name(mixer, name);
+	curve = cras_card_config_get_volume_curve_for_control(config, name);
 	if (curve)
 		return curve;
 
 	/* Use alsa jack's name as key to get volume curve. */
 	name = cras_alsa_jack_get_name(jack);
-	curve = cras_alsa_mixer_create_volume_curve_for_name(mixer, name);
+	curve = cras_card_config_get_volume_curve_for_control(config, name);
 	if (curve)
 		return curve;
 
@@ -1339,9 +1340,10 @@
 			       jack_name, node->base.name);
 
 		/* If we already have the node, associate with the jack. */
-		node->jack_curve = create_volume_curve_for_jack(aio->mixer,
-								jack);
 		node->jack = jack;
+		if (node->volume_curve == NULL)
+			node->volume_curve = create_volume_curve_for_jack(
+					aio->config, jack);
 	}
 
 	syslog(LOG_DEBUG, "%s plugged: %d, %s", jack_name, plugged,
@@ -1726,6 +1728,7 @@
 				     enum CRAS_ALSA_CARD_TYPE card_type,
 				     int is_first,
 				     struct cras_alsa_mixer *mixer,
+				     const struct cras_card_config *config,
 				     struct cras_use_case_mgr *ucm,
 				     snd_hctl_t *hctl,
 				     enum CRAS_STREAM_DIRECTION direction,
@@ -1809,6 +1812,15 @@
 		goto cleanup_iodev;
 
 	aio->mixer = mixer;
+	aio->config = config;
+	if (direction == CRAS_STREAM_OUTPUT) {
+		aio->default_volume_curve =
+				cras_card_config_get_volume_curve_for_control(
+						config, "Default");
+		if (aio->default_volume_curve == NULL)
+			aio->default_volume_curve =
+					cras_volume_curve_create_default();
+	}
 	aio->ucm = ucm;
 	if (ucm) {
 		unsigned int level;
@@ -2008,8 +2020,10 @@
 	if (jack) {
 		if (output_node) {
 			output_node->jack = jack;
-			output_node->jack_curve =
-				create_volume_curve_for_jack(aio->mixer, jack);
+			if (!output_node->volume_curve)
+				output_node->volume_curve =
+					create_volume_curve_for_jack(
+						aio->config, jack);
 		} else if (input_node) {
 			input_node->jack = jack;
 		}
@@ -2062,6 +2076,7 @@
 
 	/* Free resources when device successfully removed. */
 	free_alsa_iodev_resources(aio);
+	cras_volume_curve_destroy(aio->default_volume_curve);
 	free(iodev);
 }
 
diff --git a/cras/src/server/cras_alsa_io.h b/cras/src/server/cras_alsa_io.h
index ce2fd97..0b3e548 100644
--- a/cras/src/server/cras_alsa_io.h
+++ b/cras/src/server/cras_alsa_io.h
@@ -8,6 +8,7 @@
 
 #include <alsa/asoundlib.h>
 
+#include "cras_card_config.h"
 #include "cras_types.h"
 
 struct cras_alsa_mixer;
@@ -25,6 +26,7 @@
  *    card_type - the type of the card this iodev belongs.
  *    is_first - if this is the first iodev on the card.
  *    mixer - The mixer for the alsa device.
+ *    config - Card config for this alsa device.
  *    ucm - CRAS use case manager if available.
  *    hctl - high-level control manager if available.
  *    direction - input or output.
@@ -42,6 +44,7 @@
 				     enum CRAS_ALSA_CARD_TYPE card_type,
 				     int is_first,
 				     struct cras_alsa_mixer *mixer,
+				     const struct cras_card_config *config,
 				     struct cras_use_case_mgr *ucm,
 				     snd_hctl_t *hctl,
 				     enum CRAS_STREAM_DIRECTION direction,
diff --git a/cras/src/server/cras_alsa_mixer.c b/cras/src/server/cras_alsa_mixer.c
index dc9d21f..920251c 100644
--- a/cras/src/server/cras_alsa_mixer.c
+++ b/cras/src/server/cras_alsa_mixer.c
@@ -11,9 +11,7 @@
 #include "cras_alsa_mixer.h"
 #include "cras_alsa_mixer_name.h"
 #include "cras_alsa_ucm.h"
-#include "cras_card_config.h"
 #include "cras_util.h"
-#include "cras_volume_curve.h"
 #include "utlist.h"
 
 #define MIXER_CONTROL_VOLUME_DB_INVALID LONG_MAX
@@ -57,7 +55,6 @@
  * has_mute - non-zero indicates there is a mute switch.
  * max_volume_dB - Maximum volume available in the volume control.
  * min_volume_dB - Minimum volume available in the volume control.
- * volume_curve - Volume curve for this control.
  */
 struct mixer_control {
 	const char *name;
@@ -67,7 +64,6 @@
 	int has_mute;
 	long max_volume_dB;
 	long min_volume_dB;
-	struct cras_volume_curve *volume_curve;
 	struct mixer_control *prev, *next;
 };
 
@@ -77,11 +73,9 @@
  * playback_switch - Switch used to mute the device.
  * main_capture_controls - List of capture gain controls (normally 'Capture').
  * capture_switch - Switch used to mute the capture stream.
- * volume_curve - Default volume curve that converts from an index to dBFS.
  * max_volume_dB - Maximum volume available in main volume controls.  The dBFS
  *   value setting will be applied relative to this.
  * min_volume_dB - Minimum volume available in main volume controls.
- * config - Config info for this card, can be NULL if none found.
  */
 struct cras_alsa_mixer {
 	snd_mixer_t *mixer;
@@ -91,10 +85,8 @@
 	struct mixer_control *main_capture_controls;
 	struct mixer_control *input_controls;
 	snd_mixer_elem_t *capture_switch;
-	struct cras_volume_curve *volume_curve;
 	long max_volume_dB;
 	long min_volume_dB;
-	const struct cras_card_config *config;
 };
 
 /* Wrapper for snd_mixer_open and helpers.
@@ -193,8 +185,6 @@
 	}
 	if (control->name)
 		free((void *)control->name);
-	if (control->volume_curve)
-		cras_volume_curve_destroy(control->volume_curve);
 	free(control);
 }
 
@@ -528,14 +518,6 @@
 	return 0;
 }
 
-/* Creates a volume curve for a new output. */
-static struct cras_volume_curve *create_volume_curve_for_output(
-		const struct cras_alsa_mixer *cmix, const char* output_name)
-{
-	return cras_card_config_get_volume_curve_for_control(
-			cmix->config, output_name);
-}
-
 /* Adds a control to the list. */
 static int add_control_with_name(struct cras_alsa_mixer *cmix,
 				 enum CRAS_STREAM_DIRECTION dir,
@@ -559,14 +541,10 @@
 		syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
 		       c->name, c->min_volume_dB, c->max_volume_dB);
 
-	if (dir == CRAS_STREAM_OUTPUT) {
-		c->volume_curve =
-			create_volume_curve_for_output(cmix, c->name);
+	if (dir == CRAS_STREAM_OUTPUT)
 		DL_APPEND(cmix->output_controls, c);
-	}
-	else if (dir == CRAS_STREAM_INPUT) {
+	else if (dir == CRAS_STREAM_INPUT)
 		DL_APPEND(cmix->input_controls, c);
-	}
 	return 0;
 }
 
@@ -624,14 +602,10 @@
 		syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
 		       c->name, c->min_volume_dB, c->max_volume_dB);
 
-	if (dir == CRAS_STREAM_OUTPUT) {
-		c->volume_curve =
-			create_volume_curve_for_output(cmix, c->name);
+	if (dir == CRAS_STREAM_OUTPUT)
 		DL_APPEND(cmix->output_controls, c);
-	}
-	else if (dir == CRAS_STREAM_INPUT) {
+	else if (dir == CRAS_STREAM_INPUT)
 		DL_APPEND(cmix->input_controls, c);
-	}
 	return 0;
 }
 
@@ -659,14 +633,10 @@
 		syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
 		       c->name, c->min_volume_dB, c->max_volume_dB);
 
-	if (dir == CRAS_STREAM_OUTPUT) {
-		c->volume_curve =
-			create_volume_curve_for_output(cmix, c->name);
+	if (dir == CRAS_STREAM_OUTPUT)
 		DL_APPEND(cmix->output_controls, c);
-	}
-	else if (dir == CRAS_STREAM_INPUT) {
+	else if (dir == CRAS_STREAM_INPUT)
 		DL_APPEND(cmix->input_controls, c);
-	}
 	return 0;
 }
 
@@ -674,9 +644,7 @@
  * Exported interface.
  */
 
-struct cras_alsa_mixer *cras_alsa_mixer_create(
-		const char *card_name,
-		const struct cras_card_config *config)
+struct cras_alsa_mixer *cras_alsa_mixer_create(const char *card_name)
 {
 	struct cras_alsa_mixer *cmix;
 
@@ -686,13 +654,6 @@
 
 	syslog(LOG_DEBUG, "Add mixer for device %s", card_name);
 
-	cmix->config = config;
-	cmix->volume_curve =
-		cras_card_config_get_volume_curve_for_control(cmix->config,
-							      "Default");
-	if (cmix->volume_curve == NULL)
-		cmix->volume_curve = cras_volume_curve_create_default();
-
 	alsa_mixer_open(card_name, &cmix->mixer);
 
 	return cmix;
@@ -944,20 +905,11 @@
 	mixer_control_destroy_list(cras_mixer->main_capture_controls);
 	mixer_control_destroy_list(cras_mixer->output_controls);
 	mixer_control_destroy_list(cras_mixer->input_controls);
-	cras_volume_curve_destroy(cras_mixer->volume_curve);
 	if (cras_mixer->mixer)
 		snd_mixer_close(cras_mixer->mixer);
 	free(cras_mixer);
 }
 
-const struct cras_volume_curve *cras_alsa_mixer_default_volume_curve(
-		const struct cras_alsa_mixer *cras_mixer)
-{
-	assert(cras_mixer);
-	assert(cras_mixer->volume_curve);
-	return cras_mixer->volume_curve;
-}
-
 int cras_alsa_mixer_has_main_volume(
 		const struct cras_alsa_mixer *cras_mixer)
 {
@@ -1218,22 +1170,3 @@
 		return -1;
 	return mixer_control_set_mute(output, !active);
 }
-
-struct cras_volume_curve *cras_alsa_mixer_create_volume_curve_for_name(
-		const struct cras_alsa_mixer *cmix,
-		const char *name)
-{
-	if (!cmix)
-		return NULL;
-	return cras_card_config_get_volume_curve_for_control(
-			cmix->config, name);
-}
-
-struct cras_volume_curve *cras_alsa_mixer_get_output_volume_curve(
-		const struct mixer_control *output)
-{
-	if (output)
-		return output->volume_curve;
-	else
-		return NULL;
-}
diff --git a/cras/src/server/cras_alsa_mixer.h b/cras/src/server/cras_alsa_mixer.h
index 58b59b0..a6b490f 100644
--- a/cras/src/server/cras_alsa_mixer.h
+++ b/cras/src/server/cras_alsa_mixer.h
@@ -27,15 +27,12 @@
  * Args:
  *    card_name - Name of the card to open a mixer for.  This is an alsa name of
  *      the form "hw:X" where X ranges from 0 to 31 inclusive.
- *    config - Config info for this card, can be NULL if none found.
  * Returns:
  *    A pointer to the newly created cras_alsa_mixer which must later be freed
  *    by calling cras_alsa_mixer_destroy. The control in the mixer is not added
  *    yet.
  */
-struct cras_alsa_mixer *cras_alsa_mixer_create(
-		const char *card_name,
-		const struct cras_card_config *config);
+struct cras_alsa_mixer *cras_alsa_mixer_create(const char *card_name);
 
 /* Adds controls to a cras_alsa_mixer from the given UCM section.
  * Args:
@@ -68,12 +65,6 @@
  */
 void cras_alsa_mixer_destroy(struct cras_alsa_mixer *cras_mixer);
 
-/* Gets the default volume curve for this mixer.  This curve will be used if
- * there is not output-node specific curve to use.
- */
-const struct cras_volume_curve *cras_alsa_mixer_default_volume_curve(
-		const struct cras_alsa_mixer *mixer);
-
 /* Returns if the mixer has any main volume control. */
 int cras_alsa_mixer_has_main_volume(const struct cras_alsa_mixer *cras_mixer);
 
@@ -240,16 +231,4 @@
 		struct mixer_control *output,
 		int active);
 
-/* Returns a volume curve for the given name.  The name can be that of a
- * control or of a Jack.  Looks for an entry in the ini file (See README
- * for format), or return NULL if the ini file doesn't specify a curve for
- * this name. */
-struct cras_volume_curve *cras_alsa_mixer_create_volume_curve_for_name(
-		const struct cras_alsa_mixer *cmix,
-		const char *name);
-
-/* Returns a volume curve stored in the output control element, can be null. */
-struct cras_volume_curve *cras_alsa_mixer_get_output_volume_curve(
-		const struct mixer_control *control);
-
 #endif /* _CRAS_ALSA_MIXER_H */
diff --git a/cras/src/tests/alsa_card_unittest.cc b/cras/src/tests/alsa_card_unittest.cc
index 8bc26fe..741c6b4 100644
--- a/cras/src/tests/alsa_card_unittest.cc
+++ b/cras/src/tests/alsa_card_unittest.cc
@@ -814,8 +814,7 @@
 /* Stubs */
 
 extern "C" {
-struct cras_alsa_mixer *cras_alsa_mixer_create(
-    const char *card_name, const struct cras_card_config *config) {
+struct cras_alsa_mixer *cras_alsa_mixer_create(const char *card_name) {
   cras_alsa_mixer_create_called++;
   return cras_alsa_mixer_create_return;
 }
@@ -849,7 +848,8 @@
 				     enum CRAS_ALSA_CARD_TYPE card_type,
 				     int is_first,
 				     struct cras_alsa_mixer *mixer,
-                                     struct cras_use_case_mgr *ucm,
+				     const struct cras_card_config *config,
+				     struct cras_use_case_mgr *ucm,
 				     snd_hctl_t *hctl,
 				     enum CRAS_STREAM_DIRECTION direction,
 				     size_t usb_vid,
diff --git a/cras/src/tests/alsa_io_unittest.cc b/cras/src/tests/alsa_io_unittest.cc
index c07e203..969bae6 100644
--- a/cras/src/tests/alsa_io_unittest.cc
+++ b/cras/src/tests/alsa_io_unittest.cc
@@ -65,6 +65,7 @@
 static size_t sys_get_capture_mute_called;
 static int sys_get_capture_mute_return_value;
 static struct cras_alsa_mixer *fake_mixer = (struct cras_alsa_mixer *)1;
+static struct cras_card_config *fake_config = (struct cras_card_config *)2;
 static struct mixer_control **cras_alsa_mixer_list_outputs_outputs;
 static size_t cras_alsa_mixer_list_outputs_outputs_length;
 static struct mixer_control **cras_alsa_mixer_list_inputs_outputs;
@@ -73,10 +74,6 @@
 static std::vector<struct mixer_control *>
     cras_alsa_mixer_set_output_active_state_outputs;
 static std::vector<int> cras_alsa_mixer_set_output_active_state_values;
-static size_t cras_alsa_mixer_create_volume_curve_for_name_called;
-static struct cras_volume_curve *
-    cras_alsa_mixer_create_volume_curve_for_name_value = NULL;
-static size_t cras_alsa_mixer_default_volume_curve_called;
 static cras_audio_format *fake_format;
 static size_t sys_set_volume_limits_called;
 static size_t sys_set_capture_gain_limits_called;
@@ -88,8 +85,6 @@
 typedef std::map<const struct mixer_control*, std::string> ControlNameMap;
 static ControlNameMap cras_alsa_mixer_get_control_name_values;
 static size_t cras_alsa_mixer_get_control_name_called;
-typedef std::map<const struct mixer_control*, struct cras_volume_curve*> VolumeCurveMap;
-static VolumeCurveMap cras_alsa_mixer_get_output_volume_curve_values;
 static size_t cras_alsa_jack_list_create_called;
 static size_t cras_alsa_jack_list_find_jacks_by_name_matching_called;
 static size_t cras_alsa_jack_list_add_jack_for_section_called;
@@ -138,6 +133,9 @@
 static snd_hctl_t *fake_hctl = (snd_hctl_t *)2;
 static size_t ucm_get_dma_period_for_dev_called;
 static unsigned int ucm_get_dma_period_for_dev_ret;
+static int cras_card_config_get_volume_curve_for_control_called;
+typedef std::map<std::string, struct cras_volume_curve *> VolCurveMap;
+static VolCurveMap cras_card_config_get_volume_curve_vals;
 static int cras_alsa_mmap_get_whole_buffer_called;
 static int cras_iodev_fill_odev_zeros_called;
 static unsigned int cras_iodev_fill_odev_zeros_frames;
@@ -175,15 +173,12 @@
   cras_alsa_mixer_set_output_active_state_called = 0;
   cras_alsa_mixer_set_output_active_state_outputs.clear();
   cras_alsa_mixer_set_output_active_state_values.clear();
-  cras_alsa_mixer_create_volume_curve_for_name_called = 0;
-  cras_alsa_mixer_default_volume_curve_called = 0;
   sys_set_volume_limits_called = 0;
   sys_set_capture_gain_limits_called = 0;
   sys_get_capture_gain_return_value = 0;
   cras_alsa_mixer_get_minimum_capture_gain_called = 0;
   cras_alsa_mixer_get_maximum_capture_gain_called = 0;
   cras_alsa_mixer_get_output_volume_curve_called = 0;
-  cras_alsa_mixer_get_output_volume_curve_values.clear();
   cras_alsa_jack_get_mixer_output_ret = NULL;
   cras_alsa_jack_get_mixer_input_ret = NULL;
   cras_alsa_mixer_get_control_name_values.clear();
@@ -216,6 +211,8 @@
   ucm_get_max_software_gain_called = 0;
   ucm_get_max_software_gain_ret_value = -1;
   ucm_get_max_software_gain_value = 0;
+  cras_card_config_get_volume_curve_for_control_called = 0;
+  cras_card_config_get_volume_curve_vals.clear();
   cras_system_set_capture_gain_limits_set_value[0] = -1;
   cras_system_set_capture_gain_limits_set_value[1] = -1;
   cras_alsa_mixer_get_minimum_capture_gain_ret_value = 0;
@@ -241,7 +238,7 @@
   fake_get_dBFS_volume_curve_val = curve;
   return (volume - 100) * 100;
 }
-static cras_volume_curve fake_curve = {
+static cras_volume_curve default_curve = {
   .get_dBFS = fake_get_dBFS,
 };
 
@@ -251,11 +248,12 @@
     enum CRAS_ALSA_CARD_TYPE card_type,
     int is_first,
     struct cras_alsa_mixer *mixer,
+    struct cras_card_config *config,
     struct cras_use_case_mgr *ucm,
     enum CRAS_STREAM_DIRECTION direction) {
   return alsa_iodev_create(card_index, test_card_name, 0, test_dev_name,
                            dev_id, card_type, is_first,
-                           mixer, ucm, fake_hctl,
+                           mixer, config, ucm, fake_hctl,
                            direction, 0, 0, (char *)"123");
 }
 
@@ -265,7 +263,7 @@
   struct alsa_io *aio;
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL,
       CRAS_NUM_DIRECTIONS);
   ASSERT_EQ(aio, (void *)NULL);
 }
@@ -276,9 +274,11 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, test_dev_id, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL,
+      0, test_dev_id, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  /* Get volume curve twice for iodev, and default node. */
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_fill_properties_called);
   EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called);
@@ -302,10 +302,10 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("(default)", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   ASSERT_EQ((void *)no_stream, (void *)aio->base.no_stream);
@@ -313,10 +313,10 @@
   alsa_iodev_destroy((struct cras_iodev *)aio);
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("Speaker", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   ASSERT_EQ((void *)no_stream, (void *)aio->base.no_stream);
@@ -324,9 +324,11 @@
   alsa_iodev_destroy((struct cras_iodev *)aio);
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, NULL, CRAS_STREAM_INPUT);
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  /* No more call to get volume curve for input device. */
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("(default)", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   ASSERT_EQ((void *)no_stream, (void *)aio->base.no_stream);
@@ -334,9 +336,10 @@
   alsa_iodev_destroy((struct cras_iodev *)aio);
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL, CRAS_STREAM_INPUT);
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("Internal Mic", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   ASSERT_EQ((void *)no_stream, (void *)aio->base.no_stream);
@@ -350,9 +353,10 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, NULL, CRAS_STREAM_OUTPUT);
+      0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("(default)", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   EXPECT_EQ(1, cras_iodev_set_node_attr_called);
@@ -361,9 +365,10 @@
   alsa_iodev_destroy((struct cras_iodev *)aio);
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, NULL, CRAS_STREAM_INPUT);
+      0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
-
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   ASSERT_STREQ("(default)", aio->base.active_node->name);
   ASSERT_EQ(1, aio->base.active_node->plugged);
   EXPECT_EQ(2, cras_iodev_set_node_attr_called);
@@ -380,10 +385,10 @@
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
-
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   aio = (struct alsa_io *)iodev;
   format.frame_rate = 48000;
   cras_iodev_set_format(iodev, &format);
@@ -391,7 +396,6 @@
   // Test that these flags are cleared after open_dev.
   aio->is_free_running = 1;
   aio->filled_zeros_for_draining = 512;
-
   iodev->open_dev(iodev);
   EXPECT_EQ(1, cras_alsa_open_called);
   EXPECT_EQ(1, sys_set_volume_limits_called);
@@ -413,25 +417,28 @@
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(0, cras_iodev_set_node_attr_called);
   alsa_iodev_destroy(iodev);
 
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB,
-                                                    0, fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    0, fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(0, cras_iodev_set_node_attr_called);
   alsa_iodev_destroy(iodev);
 
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB,
-                                                    1, fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    1, fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   // Should assume USB devs are plugged when they appear.
   EXPECT_EQ(1, cras_iodev_set_node_attr_called);
   EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr);
@@ -446,9 +453,10 @@
   alsa_mixer_get_output_dB_range_value = 1000;
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB,
-                                                    1, fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    1, fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(1, alsa_mixer_get_dB_range_called);
   EXPECT_EQ(1, alsa_mixer_get_output_dB_range_called);
   EXPECT_EQ(1, iodev->active_node->software_volume_needed);
@@ -458,9 +466,10 @@
   alsa_mixer_get_output_dB_range_value = 2000;
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB,
-                                                    1, fake_mixer, NULL,
-                                                    CRAS_STREAM_OUTPUT);
+                                                    1, fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(1, alsa_mixer_get_dB_range_called);
   EXPECT_EQ(1, alsa_mixer_get_output_dB_range_called);
   EXPECT_EQ(0, iodev->active_node->software_volume_needed);
@@ -477,7 +486,8 @@
   ucm_get_max_software_gain_value = 2000;
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
   EXPECT_EQ(1, iodev->active_node->software_volume_needed);
@@ -496,7 +506,8 @@
   cras_alsa_mixer_get_maximum_capture_gain_ret_value = 500;
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
   EXPECT_EQ(0, iodev->active_node->software_volume_needed);
@@ -515,10 +526,11 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_NE(aio, (void *)NULL);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_fill_properties_called);
   EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called);
@@ -545,9 +557,11 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, NULL, CRAS_STREAM_INPUT);
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_INPUT);
   ASSERT_NE(aio, (void *)NULL);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+
   EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_fill_properties_called);
   EXPECT_EQ(1, cras_alsa_jack_list_create_called);
@@ -572,9 +586,11 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL, CRAS_STREAM_INPUT);
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
+      CRAS_STREAM_INPUT);
   ASSERT_NE(aio, (void *)NULL);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+
   EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_fill_properties_called);
   EXPECT_EQ(1, cras_alsa_mixer_list_inputs_called);
@@ -589,8 +605,8 @@
 
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    fake_mixer, NULL,
-                                                    CRAS_STREAM_INPUT);
+                                                    fake_mixer, fake_config,
+                                                    NULL, CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
 
   aio = (struct alsa_io *)iodev;
@@ -627,7 +643,8 @@
 
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
 
@@ -661,9 +678,11 @@
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    fake_mixer, NULL,
+                                                    fake_mixer, fake_config,
+                                                    NULL,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
 
   iodev->update_active_node(iodev, 0, 1);
 
@@ -677,9 +696,10 @@
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    NULL, NULL,
+                                                    NULL, fake_config, NULL,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
 
   // Return right away if it is already running.
   snd_pcm_state_ret = SND_PCM_STATE_RUNNING;
@@ -703,9 +723,10 @@
   ResetStubData();
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 0,
-                                                    NULL, NULL,
+                                                    NULL, fake_config, NULL,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
 
   // Attempt to resume if the device is suspended.
   snd_pcm_state_ret = SND_PCM_STATE_SUSPENDED;
@@ -724,9 +745,10 @@
   ResetStubData();
   ucm_get_dsp_name_default_value = "hello";
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(1, ucm_get_dsp_name_default_called);
   EXPECT_EQ(1, cras_alsa_jack_get_dsp_name_called);
@@ -745,7 +767,7 @@
   ucm_get_dsp_name_default_value = "default_dsp";
   cras_alsa_jack_get_dsp_name_value = "override_dsp";
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
@@ -782,7 +804,7 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
   // Add the jack node.
@@ -804,7 +826,7 @@
   ucm_swap_mode_exists_ret_value = 0;
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
 
@@ -816,7 +838,7 @@
   ucm_swap_mode_exists_ret_value = 1;
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
   // Enable swap mode.
@@ -842,9 +864,11 @@
   cras_alsa_mixer_list_outputs_outputs = outputs;
   cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs);
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  /* Two mixer controls calls get volume curve. */
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called);
 
@@ -880,15 +904,12 @@
   cras_alsa_mixer_list_outputs_outputs = outputs;
   cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs);
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, NULL,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called);
-  // This will be called three times because there will be
-  // two default node (because the output control's name is "")
-  // and one speaker node (because it is the first internal device).
-  EXPECT_EQ(3, cras_alsa_mixer_get_output_volume_curve_called);
 
   aio->handle = (snd_pcm_t *)0x24;
 
@@ -927,10 +948,11 @@
 
   // Create the iodev
   iodev = alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
+  EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called);
 
   // First node 'Headphone'
   section = ucm_section_create("Headphone", 0, CRAS_STREAM_OUTPUT,
@@ -940,6 +962,7 @@
       reinterpret_cast<struct cras_alsa_jack *>(10);
   cras_alsa_mixer_get_control_for_section_return_value = output;
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   ucm_section_free_list(section);
 
   // Second node 'Line Out'
@@ -950,6 +973,7 @@
       reinterpret_cast<struct cras_alsa_jack *>(20);
   cras_alsa_mixer_get_control_for_section_return_value = output;
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
+  EXPECT_EQ(7, cras_card_config_get_volume_curve_for_control_called);
   ucm_section_free_list(section);
 
   // Both nodes are associated with the same mixer output. Different jack plug
@@ -986,10 +1010,12 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
+  EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called);
 
   // First node.
   section = ucm_section_create(INTERNAL_SPEAKER, 0, CRAS_STREAM_OUTPUT,
@@ -1000,6 +1026,7 @@
   cras_alsa_mixer_get_control_for_section_return_value = outputs[0];
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
   ucm_section_free_list(section);
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
 
   // Add a second node (will use the same iodev).
   section = ucm_section_create("Headphone", 0, CRAS_STREAM_OUTPUT,
@@ -1010,6 +1037,9 @@
   cras_alsa_mixer_get_control_for_section_return_value = outputs[1];
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
   ucm_section_free_list(section);
+  /* New nodes creation calls get volume curve once, NULL jack doesn't make
+   * more calls. */
+  EXPECT_EQ(5, cras_card_config_get_volume_curve_for_control_called);
 
   // Jack plug of an unkonwn device should do nothing.
   cras_alsa_jack_get_mixer_output_ret = NULL;
@@ -1022,7 +1052,6 @@
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(2, cras_alsa_jack_list_add_jack_for_section_called);
   EXPECT_EQ(2, cras_alsa_mixer_get_control_for_section_called);
-  EXPECT_EQ(2, cras_alsa_mixer_get_output_volume_curve_called);
   EXPECT_EQ(1, ucm_get_dma_period_for_dev_called);
   EXPECT_EQ(ucm_get_dma_period_for_dev_ret, aio->dma_period_set_microsecs);
 
@@ -1064,10 +1093,12 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(1, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
+  EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called);
 
   // Node without controls or jacks.
   section = ucm_section_create(INTERNAL_SPEAKER, 1, CRAS_STREAM_OUTPUT,
@@ -1076,6 +1107,7 @@
   EXPECT_EQ(-22, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
   section->dev_idx = 0;
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
+  EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called);
   EXPECT_EQ(1, cras_iodev_add_node_called);
   ucm_section_free_list(section);
@@ -1084,7 +1116,6 @@
   alsa_iodev_ucm_complete_init(iodev);
   EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream);
   EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called);
-  EXPECT_EQ(1, cras_alsa_mixer_get_output_volume_curve_called);
   EXPECT_EQ(1, cras_iodev_update_dsp_called);
   EXPECT_EQ(0, cras_alsa_jack_enable_ucm_called);
   EXPECT_EQ(1, ucm_set_enabled_called);
@@ -1104,10 +1135,12 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(1, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_OUTPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
+  EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called);
 
   // Node without controls or jacks.
   cras_alsa_jack_list_add_jack_for_section_result_jack =
@@ -1115,10 +1148,10 @@
   section = ucm_section_create("Headphone", 0, CRAS_STREAM_OUTPUT,
       jack_name, "hctl");
   ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section));
+  EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called);
   EXPECT_EQ(1, cras_iodev_add_node_called);
   EXPECT_EQ(1, cras_alsa_jack_list_add_jack_for_section_called);
-  EXPECT_EQ(2, cras_alsa_mixer_create_volume_curve_for_name_called);
   ucm_section_free_list(section);
 
   // Complete initialization, and make first node active.
@@ -1153,7 +1186,8 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(0, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
@@ -1233,7 +1267,8 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(1, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
@@ -1274,7 +1309,8 @@
   // Create the IO device.
   iodev = alsa_iodev_create_with_default_parameters(1, NULL,
                                                     ALSA_CARD_TYPE_INTERNAL, 1,
-                                                    fake_mixer, fake_ucm,
+                                                    fake_mixer, fake_config,
+                                                    fake_ucm,
                                                     CRAS_STREAM_INPUT);
   ASSERT_NE(iodev, (void *)NULL);
   aio = reinterpret_cast<struct alsa_io *>(iodev);
@@ -1319,9 +1355,11 @@
   auto_unplug_output_node_ret = 1;
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
+
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
+  EXPECT_EQ(3, cras_card_config_get_volume_curve_for_control_called);
   EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called);
   EXPECT_EQ(2, cras_alsa_mixer_get_control_name_called);
 
@@ -1363,7 +1401,7 @@
   auto_unplug_input_node_ret = 1;
 
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_INPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
   EXPECT_EQ(1, cras_alsa_mixer_list_inputs_called);
@@ -1602,7 +1640,7 @@
 
   ResetStubData();
   aio = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
-      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_ucm,
+      0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm,
       CRAS_STREAM_OUTPUT);
   ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev *)aio));
 
@@ -1638,9 +1676,10 @@
       aio_output_ = (struct alsa_io *)alsa_iodev_create_with_default_parameters(
           0, NULL,
           ALSA_CARD_TYPE_INTERNAL, 1,
-          fake_mixer, NULL,
+          fake_mixer, fake_config, NULL,
           CRAS_STREAM_OUTPUT);
       alsa_iodev_legacy_complete_init((struct cras_iodev *)aio_output_);
+      EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called);
 
       struct cras_ionode *node;
       int count = 0;
@@ -1665,7 +1704,7 @@
   struct cras_audio_format fmt_;
 };
 
-TEST_F(AlsaVolumeMuteSuite, GetVolumeCurve) {
+TEST_F(AlsaVolumeMuteSuite, GetDefaultVolumeCurve) {
   int rc;
   struct cras_audio_format *fmt;
 
@@ -1674,31 +1713,15 @@
   aio_output_->base.format = fmt;
   aio_output_->handle = (snd_pcm_t *)0x24;
 
-  cras_alsa_mixer_get_output_volume_curve_called = 0;
-  cras_alsa_mixer_default_volume_curve_called = 0;
   rc = aio_output_->base.open_dev(&aio_output_->base);
   ASSERT_EQ(0, rc);
-  // get_curve_for_output_node() get called twice for setting volume limits
-  // and initial values.
-  EXPECT_EQ(2, cras_alsa_mixer_get_output_volume_curve_called);
-  EXPECT_EQ(2, cras_alsa_mixer_default_volume_curve_called);
+  EXPECT_EQ(&default_curve, fake_get_dBFS_volume_curve_val);
 
-  cras_alsa_mixer_get_output_volume_curve_values[output_control_] = NULL;
   aio_output_->base.set_volume(&aio_output_->base);
-  EXPECT_EQ(3, cras_alsa_mixer_get_output_volume_curve_called);
-  EXPECT_EQ(3, cras_alsa_mixer_default_volume_curve_called);
-
-  // If output control has its own volume curve, mixer default volume curve
-  // should't get called again.
-  cras_alsa_mixer_get_output_volume_curve_values[output_control_] =
-      &fake_curve;
-  aio_output_->base.set_volume(&aio_output_->base);
-  EXPECT_EQ(4, cras_alsa_mixer_get_output_volume_curve_called);
-  EXPECT_EQ(3, cras_alsa_mixer_default_volume_curve_called);
-  EXPECT_EQ(&fake_curve, fake_get_dBFS_volume_curve_val);
+  EXPECT_EQ(&default_curve, fake_get_dBFS_volume_curve_val);
 }
 
-TEST_F(AlsaVolumeMuteSuite, GetVolumeCurveFromJack)
+TEST_F(AlsaVolumeMuteSuite, GetVolumeCurveFromNode)
 {
   int rc;
   struct cras_audio_format *fmt;
@@ -1713,34 +1736,23 @@
   aio_output_->base.format = fmt;
   aio_output_->handle = (snd_pcm_t *)0x24;
 
-  cras_alsa_mixer_get_output_volume_curve_called = 0;
-  cras_alsa_mixer_default_volume_curve_called = 0;
-
   // Headphone jack plugged and has its own volume curve.
   cras_alsa_jack_get_mixer_output_ret = NULL;
   cras_alsa_jack_get_name_ret_value = "Headphone";
-  cras_alsa_mixer_create_volume_curve_for_name_value = &hp_curve;
+  cras_card_config_get_volume_curve_vals["Headphone"] = &hp_curve;
   cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data);
   EXPECT_EQ(1, cras_alsa_jack_update_node_type_called);
+  EXPECT_EQ(3, cras_card_config_get_volume_curve_for_control_called);
 
   // Switch to node 'Headphone'.
   node = aio_output_->base.nodes->next;
   aio_output_->base.active_node = node;
 
-  cras_alsa_mixer_get_output_volume_curve_called = 0;
-  cras_alsa_mixer_default_volume_curve_called = 0;
   rc = aio_output_->base.open_dev(&aio_output_->base);
   ASSERT_EQ(0, rc);
-  // Assert volume curve functions aren't called because headphone node has
-  // its own volume curve.
-  EXPECT_EQ(0, cras_alsa_mixer_get_output_volume_curve_called);
-  EXPECT_EQ(0, cras_alsa_mixer_default_volume_curve_called);
+  EXPECT_EQ(&hp_curve, fake_get_dBFS_volume_curve_val);
 
-  cras_alsa_mixer_get_output_volume_curve_values[output_control_] =
-      &fake_curve;
   aio_output_->base.set_volume(&aio_output_->base);
-  EXPECT_EQ(0, cras_alsa_mixer_get_output_volume_curve_called);
-  EXPECT_EQ(0, cras_alsa_mixer_default_volume_curve_called);
   EXPECT_EQ(&hp_curve, fake_get_dBFS_volume_curve_val);
 }
 
@@ -2305,14 +2317,6 @@
   }
 }
 
-struct cras_volume_curve *cras_alsa_mixer_create_volume_curve_for_name(
-		const struct cras_alsa_mixer *cmix,
-		const char *name)
-{
-  cras_alsa_mixer_create_volume_curve_for_name_called++;
-  return cras_alsa_mixer_create_volume_curve_for_name_value;
-}
-
 int cras_alsa_mixer_set_output_active_state(
 		struct mixer_control *output,
 		int active)
@@ -2323,13 +2327,6 @@
   return 0;
 }
 
-const struct cras_volume_curve *cras_alsa_mixer_default_volume_curve(
-		const struct cras_alsa_mixer *cras_mixer)
-{
-  cras_alsa_mixer_default_volume_curve_called++;
-  return &fake_curve;
-}
-
 void cras_volume_curve_destroy(struct cras_volume_curve *curve)
 {
 }
@@ -2350,13 +2347,6 @@
 	return cras_alsa_mixer_get_maximum_capture_gain_ret_value;
 }
 
-struct cras_volume_curve *cras_alsa_mixer_get_output_volume_curve(
-		const struct mixer_control *control)
-{
-  cras_alsa_mixer_get_output_volume_curve_called++;
-  return cras_alsa_mixer_get_output_volume_curve_values[control];
-}
-
 int cras_alsa_mixer_has_main_volume(const struct cras_alsa_mixer *cras_mixer)
 {
   return 1;
@@ -2544,6 +2534,25 @@
   return -EINVAL;
 }
 
+struct cras_volume_curve *cras_volume_curve_create_default()
+{
+  return &default_curve;
+}
+
+struct cras_volume_curve *cras_card_config_get_volume_curve_for_control(
+    const struct cras_card_config *card_config,
+    const char *control_name)
+{
+  VolCurveMap::iterator it;
+  cras_card_config_get_volume_curve_for_control_called++;
+  if (!control_name)
+    return NULL;
+  it = cras_card_config_get_volume_curve_vals.find(control_name);
+  if (it == cras_card_config_get_volume_curve_vals.end())
+    return NULL;
+  return it->second;
+}
+
 void cras_iodev_free_format(struct cras_iodev *iodev)
 {
 }
diff --git a/cras/src/tests/alsa_mixer_unittest.cc b/cras/src/tests/alsa_mixer_unittest.cc
index 91d7a26..5bae040 100644
--- a/cras/src/tests/alsa_mixer_unittest.cc
+++ b/cras/src/tests/alsa_mixer_unittest.cc
@@ -71,7 +71,6 @@
 static int snd_mixer_selem_get_capture_dB_called;
 static long *snd_mixer_selem_get_capture_dB_return_values;
 static int snd_mixer_selem_get_capture_dB_return_values_length;
-static size_t cras_card_config_get_volume_curve_for_control_called;
 static size_t cras_volume_curve_destroy_called;
 static size_t snd_mixer_selem_get_playback_dB_range_called;
 static size_t snd_mixer_selem_get_playback_dB_range_values_length;
@@ -136,7 +135,6 @@
   snd_mixer_selem_get_capture_dB_called = 0;
   snd_mixer_selem_get_capture_dB_return_values = static_cast<long *>(NULL);
   snd_mixer_selem_get_capture_dB_return_values_length = 0;
-  cras_card_config_get_volume_curve_for_control_called = 0;
   cras_volume_curve_destroy_called = 0;
   snd_mixer_selem_get_playback_dB_range_called = 0;
   snd_mixer_selem_get_playback_dB_range_values_length = 0;
@@ -153,10 +151,9 @@
 
 struct cras_alsa_mixer *create_mixer_and_add_controls_by_name_matching(
     const char *card_name,
-    const struct cras_card_config *config,
     struct mixer_name *extra_controls,
     struct mixer_name *coupled_controls) {
-  struct cras_alsa_mixer *cmix = cras_alsa_mixer_create(card_name, config);
+  struct cras_alsa_mixer *cmix = cras_alsa_mixer_create(card_name);
   cras_alsa_mixer_add_controls_by_name_matching(
       cmix, extra_controls, coupled_controls);
   return cmix;
@@ -167,7 +164,7 @@
 
   ResetStubData();
   snd_mixer_open_return_value = -1;
-  c = cras_alsa_mixer_create("hw:0", NULL);
+  c = cras_alsa_mixer_create("hw:0");
   EXPECT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
 }
@@ -177,7 +174,7 @@
 
   ResetStubData();
   snd_mixer_attach_return_value = -1;
-  c = cras_alsa_mixer_create("hw:0", NULL);
+  c = cras_alsa_mixer_create("hw:0");
   EXPECT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -190,7 +187,7 @@
 
   ResetStubData();
   snd_mixer_selem_register_return_value = -1;
-  c = cras_alsa_mixer_create("hw:0", NULL);
+  c = cras_alsa_mixer_create("hw:0");
   EXPECT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -204,7 +201,7 @@
 
   ResetStubData();
   snd_mixer_load_return_value = -1;
-  c = cras_alsa_mixer_create("hw:0", NULL);
+  c = cras_alsa_mixer_create("hw:0");
   EXPECT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -219,7 +216,7 @@
 
   ResetStubData();
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -261,7 +258,7 @@
   snd_mixer_selem_get_name_return_values = element_names;
   snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names);
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -334,7 +331,7 @@
   snd_mixer_selem_get_playback_dB_range_max_values = max_volumes;
   snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes);
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -410,7 +407,7 @@
   snd_mixer_selem_get_name_return_values = element_names;
   snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names);
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -507,7 +504,7 @@
   snd_mixer_selem_set_playback_dB_all_values_length =
       ARRAY_SIZE(set_dB_values);
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_range_called);
   EXPECT_EQ(1, snd_mixer_open_called);
@@ -633,7 +630,7 @@
   snd_mixer_selem_get_name_return_values = element_names;
   snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names);
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, NULL);
+      "hw:0", NULL, NULL);
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
   EXPECT_EQ(1, snd_mixer_attach_called);
@@ -835,9 +832,7 @@
     iniparser_getstring_returns = iniparser_returns;
     iniparser_getstring_return_length = ARRAY_SIZE(iniparser_returns);
     cras_mixer_ = create_mixer_and_add_controls_by_name_matching(
-        "hw:0",
-        reinterpret_cast<struct cras_card_config*>(5),
-        extra_controls, NULL);
+        "hw:0", extra_controls, NULL);
     ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), cras_mixer_);
     EXPECT_EQ(1, snd_mixer_open_called);
     EXPECT_EQ(1, snd_mixer_attach_called);
@@ -850,7 +845,6 @@
     EXPECT_EQ(7, snd_mixer_selem_has_playback_switch_called);
     EXPECT_EQ(4, snd_mixer_selem_has_capture_volume_called);
     EXPECT_EQ(3, snd_mixer_selem_has_capture_switch_called);
-    EXPECT_EQ(5, cras_card_config_get_volume_curve_for_control_called);
     mixer_name_free(extra_controls);
   }
 
@@ -1026,7 +1020,7 @@
   snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes);
 
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, coupled_controls);
+      "hw:0", NULL, coupled_controls);
 
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
@@ -1130,7 +1124,7 @@
   snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes);
 
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, coupled_controls);
+      "hw:0", NULL, coupled_controls);
 
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
@@ -1211,7 +1205,7 @@
   snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes);
 
   c = create_mixer_and_add_controls_by_name_matching(
-      "hw:0", NULL, NULL, coupled_controls);
+      "hw:0", NULL, coupled_controls);
 
   ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), c);
   EXPECT_EQ(1, snd_mixer_open_called);
@@ -1420,8 +1414,7 @@
     snd_mixer_selem_get_capture_dB_range_values_length =
         ARRAY_SIZE(min_volumes);
 
-    cras_mixer_ = cras_alsa_mixer_create(
-                      "hw:0", reinterpret_cast<struct cras_card_config*>(5));
+    cras_mixer_ = cras_alsa_mixer_create("hw:0");
     ASSERT_NE(static_cast<struct cras_alsa_mixer *>(NULL), cras_mixer_);
     EXPECT_EQ(1, snd_mixer_open_called);
     EXPECT_EQ(1, snd_mixer_attach_called);
@@ -1429,8 +1422,6 @@
     EXPECT_EQ(1, snd_mixer_selem_register_called);
     EXPECT_EQ(1, snd_mixer_load_called);
     EXPECT_EQ(0, snd_mixer_close_called);
-    EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called);
-    cras_card_config_get_volume_curve_for_control_called = 0;
 
     section = sections;
     EXPECT_EQ(-ENOENT,\
@@ -1459,7 +1450,6 @@
     EXPECT_EQ(3, snd_mixer_selem_has_capture_switch_called);
     EXPECT_EQ(5, snd_mixer_selem_get_playback_dB_range_called);
     EXPECT_EQ(2, snd_mixer_selem_get_capture_dB_range_called);
-    EXPECT_EQ(3, cras_card_config_get_volume_curve_for_control_called);
 
     sections_ = sections;
   }
@@ -1735,7 +1725,6 @@
 {
   struct cras_volume_curve *curve;
   curve = (struct cras_volume_curve *)calloc(1, sizeof(*curve));
-  cras_card_config_get_volume_curve_for_control_called++;
   if (curve != NULL)
     curve->get_dBFS = get_dBFS_default;
   return curve;